Several fixes to CSS, better responsive overall, improved security and error page
This commit is contained in:
parent
721e7ff3db
commit
057efb848c
2
app.vue
2
app.vue
|
|
@ -3,7 +3,7 @@
|
||||||
<NuxtRouteAnnouncer/>
|
<NuxtRouteAnnouncer/>
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<div class="px-12 flex flex-1 justify-center overflow-auto max-h-full">
|
<div class="xl:ps-12 xl:pe-12 ps-6 pe-4 flex flex-1 justify-center overflow-auto max-h-full">
|
||||||
<NuxtPage></NuxtPage>
|
<NuxtPage></NuxtPage>
|
||||||
</div>
|
</div>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<TreeRoot v-slot="{ flattenItems }" class="list-none select-none text-light-100 dark:text-dark-100 p-2 font-medium xl:text-base text-sm cursor-pointer" :items="model" :get-key="(item) => item.link ?? item.label">
|
<TreeRoot v-slot="{ flattenItems }" class="list-none select-none text-light-100 dark:text-dark-100 p-2 font-medium xl:text-base text-sm" :items="model" :get-key="(item) => item.link ?? item.label">
|
||||||
<TreeItem v-for="item in flattenItems" v-slot="{ isExpanded }" :key="item._id" :style="{ 'padding-left': `${item.level - 0.5}em` }" v-bind="item.bind" class="flex items-center px-2 outline-none relative">
|
<TreeItem v-for="item in flattenItems" v-slot="{ isExpanded }" :key="item._id" :style="{ 'padding-left': `${item.level - 0.5}em` }" v-bind="item.bind" class="flex items-center px-2 outline-none relative cursor-pointer">
|
||||||
<NuxtLink :href="item.value.link && !item.hasChildren ? { name: 'explore-path', params: { path: item.value.link } } : undefined" no-prefetch class="flex flex-1 items-center" active-class="text-accent-blue">
|
<NuxtLink :href="item.value.link && !item.hasChildren ? { name: 'explore-path', params: { path: item.value.link } } : undefined" no-prefetch class="flex flex-1 items-center" active-class="text-accent-blue">
|
||||||
<Icon v-if="item.hasChildren" icon="radix-icons:chevron-right" :class="{ 'rotate-90': isExpanded }" class="h-4 w-4 transition-transform absolute" :style="{ 'left': `${item.level - 1}em` }" />
|
<Icon v-if="item.hasChildren" icon="radix-icons:chevron-right" :class="{ 'rotate-90': isExpanded }" class="h-4 w-4 transition-transform absolute" :style="{ 'left': `${item.level - 1}em` }" />
|
||||||
<div class="pl-3 py-1 flex-1 truncate border-light-35 dark:border-dark-35 hover:border-accent-blue" :class="{ 'border-s': !item.hasChildren }" :data-tag="item.value.tag">
|
<div class="pl-3 py-1 flex-1 truncate border-light-35 dark:border-dark-35 hover:border-accent-blue" :class="{ 'border-s': !item.hasChildren }" :data-tag="item.value.tag">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<slot v-bind="$attrs"></slot>
|
<span class="text-accent-blue inline-flex items-center cursor-pointer hover:text-opacity-85"><slot v-bind="$attrs"></slot></span>
|
||||||
<!-- <Suspense suspensible>
|
<!-- <Suspense suspensible>
|
||||||
<NuxtLink no-prefetch class="text-accent-blue inline-flex items-center" v-if="data && data[0]"
|
<NuxtLink no-prefetch class="text-accent-blue inline-flex items-center" v-if="data && data[0]"
|
||||||
:to="{ path: `/explorer/${project}/${data[0].path}`, hash: hash }" :class="class">
|
:to="{ path: `/explorer/${project}/${data[0].path}`, hash: hash }" :class="class">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<h1 :id="parseId(id)" class="text-5xl font-thin mt-3 mb-8 first:pt-0 pt-2 relative sm:right-8 right-4">
|
<h1 :id="parseId(id)" class="text-5xl font-thin mt-3 mb-8 first:pt-0 pt-2 relative lg:right-8 sm:right-4 right-2">
|
||||||
<slot />
|
<slot />
|
||||||
</h1>
|
</h1>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,9 @@
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</HoverPopup> -->
|
</HoverPopup> -->
|
||||||
<slot />
|
<span class="before:content-['#'] cursor-default bg-accent-blue bg-opacity-10 hover:bg-opacity-20 text-accent-blue text-sm px-1 ms-1 pb-0.5 rounded-full rounded-se-none border border-accent-blue border-opacity-30">
|
||||||
|
<slot></slot>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- <script setup lang="ts">
|
<!-- <script setup lang="ts">
|
||||||
|
|
|
||||||
BIN
db.sqlite-shm
BIN
db.sqlite-shm
Binary file not shown.
BIN
db.sqlite-wal
BIN
db.sqlite-wal
Binary file not shown.
|
|
@ -0,0 +1,22 @@
|
||||||
|
<template>
|
||||||
|
<div class="text-light-100 dark:text-dark-100 flex bg-light-0 dark:bg-dark-0 h-screen overflow-hidden justify-center items-center flex-col gap-4">
|
||||||
|
<NuxtRouteAnnouncer/>
|
||||||
|
<div class="flex gap-4 items-center">
|
||||||
|
<Icon icon="si:error-line" class="w-12 h-12 text-light-60 dark:text-dark-60"/>
|
||||||
|
<div class="text-3xl">Une erreur est survenue.</div>
|
||||||
|
</div>
|
||||||
|
<pre class="">Erreur {{ error?.statusCode }}: {{ error?.message }}</pre>
|
||||||
|
<NuxtLink :href="{ name: 'index' }"><Button>Revenir en lieu sûr</Button></NuxtLink>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { NuxtError } from '#app'
|
||||||
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
error: Object as () => NuxtError
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleError = () => clearError({ redirect: '/' })
|
||||||
|
</script>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<CollapsibleRoot class="flex flex-1 flex-col" v-model="open">
|
<CollapsibleRoot class="flex flex-1 flex-col" :v-model="open">
|
||||||
<div class="z-50 md:hidden flex w-full items-center justify-between h-12 border-b border-light-35 dark:border-dark-35">
|
<div class="z-50 md:hidden flex w-full items-center justify-between h-12 border-b border-light-35 dark:border-dark-35">
|
||||||
<div class="flex items-center px-2">
|
<div class="flex items-center px-2">
|
||||||
<CollapsibleTrigger asChild>
|
<CollapsibleTrigger asChild>
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<div class="flex items-center px-2">
|
<div class="flex items-center px-2">
|
||||||
<Tooltip message="Changer de theme" side="left"><ThemeSwitch /></Tooltip>
|
<Tooltip message="Changer de theme" side="left"><ThemeSwitch /></Tooltip>
|
||||||
<Tooltip :message="loggedIn ? 'Mon profil' : 'Se connecter'" side="right">
|
<Tooltip :message="loggedIn ? 'Mon profil' : 'Se connecter'" side="right">
|
||||||
<NuxtLink class="" :to="{ path: '/user/profile', force: true }">
|
<NuxtLink class="" :to="{ name: 'user-profile' }">
|
||||||
<div class="hover:border-opacity-70 flex">
|
<div class="hover:border-opacity-70 flex">
|
||||||
<Icon :icon="loggedIn ? 'radix-icons:avatar' : 'radix-icons:person'" class="w-7 h-7 p-1" />
|
<Icon :icon="loggedIn ? 'radix-icons:avatar' : 'radix-icons:person'" class="w-7 h-7 p-1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -27,12 +27,13 @@
|
||||||
<div class="relative bottom-6 flex flex-col gap-4 xl:px-6 px-3">
|
<div class="relative bottom-6 flex flex-col gap-4 xl:px-6 px-3">
|
||||||
<div class="flex justify-between items-center max-md:hidden">
|
<div class="flex justify-between items-center max-md:hidden">
|
||||||
<NuxtLink class=" text-light-100 dark:text-dark-100 hover:text-opacity-70 max-md:ps-6" aria-label="Accueil" :to="{ path: '/', force: true }">
|
<NuxtLink class=" text-light-100 dark:text-dark-100 hover:text-opacity-70 max-md:ps-6" aria-label="Accueil" :to="{ path: '/', force: true }">
|
||||||
<Avatar src="/logo.svg" />
|
<Avatar src="/logo.dark.svg" class="dark:block hidden" />
|
||||||
|
<Avatar src="/logo.light.svg" class="block dark:hidden" />
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<div class="flex gap-4 items-center">
|
<div class="flex gap-4 items-center">
|
||||||
<Tooltip message="Changer de theme" side="left"><ThemeSwitch /></Tooltip>
|
<Tooltip message="Changer de theme" side="left"><ThemeSwitch /></Tooltip>
|
||||||
<Tooltip :message="loggedIn ? 'Mon profil' : 'Se connecter'" side="right">
|
<Tooltip :message="loggedIn ? 'Mon profil' : 'Se connecter'" side="right">
|
||||||
<NuxtLink class="" :to="{ path: '/user/profile', force: true }">
|
<NuxtLink class="" :to="{ name: 'user-profile' }">
|
||||||
<div class="bg-light-20 dark:bg-dark-20 hover:border-opacity-70 flex border p-px border-light-50 dark:border-dark-50">
|
<div class="bg-light-20 dark:bg-dark-20 hover:border-opacity-70 flex border p-px border-light-50 dark:border-dark-50">
|
||||||
<Icon :icon="loggedIn ? 'radix-icons:avatar' : 'radix-icons:person'" class="w-7 h-7 p-1" />
|
<Icon :icon="loggedIn ? 'radix-icons:avatar' : 'radix-icons:person'" class="w-7 h-7 p-1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -43,7 +44,7 @@
|
||||||
</div>
|
</div>
|
||||||
<Tree v-if="pages" v-model="pages" class="flex-1 xl:px-6 px-3 max-w-full max-h-full overflow-y-auto overflow-x-hidden"/>
|
<Tree v-if="pages" v-model="pages" class="flex-1 xl:px-6 px-3 max-w-full max-h-full overflow-y-auto overflow-x-hidden"/>
|
||||||
<div class="xl:px-12 px-6 text-start text-xs text-light-60 dark:text-dark-60 relative top-4">
|
<div class="xl:px-12 px-6 text-start text-xs text-light-60 dark:text-dark-60 relative top-4">
|
||||||
<NuxtLink class="hover:underline italic" :to="{ path: '/legal', force: true }">Mentions légales</NuxtLink>
|
<NuxtLink class="hover:underline italic" :to="{ name: 'legal' }">Mentions légales</NuxtLink>
|
||||||
<p>Copyright Peaceultime - 2024</p>
|
<p>Copyright Peaceultime - 2024</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -63,6 +64,12 @@ const { data: pages } = await useLazyFetch('/api/navigation', {
|
||||||
transform: transform,
|
transform: transform,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(useRouter().currentRoute, () => {
|
||||||
|
console.log(open.value);
|
||||||
|
console.log('Changing');
|
||||||
|
open.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
function transform(list: any[]): any[]
|
function transform(list: any[]): any[]
|
||||||
{
|
{
|
||||||
return list?.map(e => ({ label: e.title, children: transform(e.children), link: e.path, tag: e.private ? 'Privé' : e.type }))
|
return list?.map(e => ({ label: e.title, children: transform(e.children), link: e.path, tag: e.private ? 'Privé' : e.type }))
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ async function fetch()
|
||||||
<ProseH2>Administration</ProseH2>
|
<ProseH2>Administration</ProseH2>
|
||||||
<Select label="Job" v-model="job">
|
<Select label="Job" v-model="job">
|
||||||
<SelectItem label="Synchroniser" value="sync" />
|
<SelectItem label="Synchroniser" value="sync" />
|
||||||
<SelectItem label="Nettoyer la base" value="clear" />
|
<SelectItem label="Nettoyer la base" value="clear" disabled />
|
||||||
<SelectItem label="Reconstruire" value="rebuild" disabled />
|
<SelectItem label="Reconstruire" value="rebuild" disabled />
|
||||||
</Select>
|
</Select>
|
||||||
<Button class="self-center" @click="() => !!job && fetch()" :loading="status === 'pending'">
|
<Button class="self-center" @click="() => !!job && fetch()" :loading="status === 'pending'">
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,39 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="status === 'pending'" class="flex"><Loading /></div>
|
<div v-if="status === 'pending'" class="flex">
|
||||||
<div class="flex flex-1 justify-start items-start" v-if="page">
|
<Head>
|
||||||
|
<Title>d[any] - Chargement</Title>
|
||||||
|
</Head>
|
||||||
|
<Loading />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-1 justify-start items-start" v-else-if="page">
|
||||||
|
<Head>
|
||||||
|
<Title>d[any] - {{ page.title }}</Title>
|
||||||
|
</Head>
|
||||||
<template v-if="page.type === 'markdown'">
|
<template v-if="page.type === 'markdown'">
|
||||||
<div class="flex flex-1 justify-start items-start flex-col px-24 py-6">
|
<div class="flex flex-1 justify-start items-start flex-col xl:px-24 md:px-8 px-4 py-6">
|
||||||
<div class="flex flex-1 flex-row justify-between items-center">
|
<div class="flex flex-1 flex-row justify-between items-center">
|
||||||
<ProseH1>{{ page.title }}</ProseH1>
|
<ProseH1>{{ page.title }}</ProseH1>
|
||||||
<Button v-if="isOwner"><NuxtLink :href="{ name: 'explore-edit-path', params: { path: path } }">Modifier</NuxtLink></Button>
|
<NuxtLink :href="{ name: 'explore-edit-path', params: { path: path } }"><Button v-if="isOwner">Modifier</Button></NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
<Markdown :content="page.content" />
|
<Markdown :content="page.content" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<span>Contenu non traitable</span>
|
<span>En cours de développement</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="status === 'pending'"><Loading /></div>
|
<div v-else-if="status === 'error'">
|
||||||
<div v-else-if="status === 'error'">{{ error?.message }}</div>
|
<Head>
|
||||||
<div v-else>Impossible de retrouver le contenu demandé</div>
|
<Title>d[any] - Erreur</Title>
|
||||||
|
</Head>
|
||||||
|
<span>{{ error?.message }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<Head>
|
||||||
|
<Title>d[any] - Erreur</Title>
|
||||||
|
</Head>
|
||||||
|
<div><ProseH2>Impossible d'afficher le contenu demandé</ProseH2></div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,35 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="page" class="p-12 flex flex-1 flex-col items-start justify-start">
|
<div v-if="page" class="xl:p-12 lg:p-8 py-4 flex flex-1 flex-col items-start justify-start max-h-full">
|
||||||
<Head>
|
<Head>
|
||||||
<Title>Modification de {{ page.title }}</Title>
|
<Title>Modification de {{ page.title }}</Title>
|
||||||
</Head>
|
</Head>
|
||||||
<div class="flex justify-between items-center w-full px-4 max-h-full">
|
<div class="flex flex-col xl:flex-row xl:justify-between justify-center items-center w-full px-4 pb-4 border-b border-light-35 dark:border-dark-35 bg-light-0 dark:bg-dark-0">
|
||||||
<div class="flex gap-16 items-center justify-start">
|
<input type="text" v-model="page.title" placeholder="Titre" class="flex-1 mx-4 h-16 caret-light-50 dark:caret-dark-50 text-light-100 dark:text-dark-100 placeholder:text-light-50 dark:placeholder:text-dark-50 appearance-none outline-none px-3 py-1 text-5xl font-thin bg-transparent" />
|
||||||
<input type="text" v-model="page.title" placeholder="Titre" class="mx-4 h-16 caret-light-50 dark:caret-dark-50 text-light-100 dark:text-dark-100 placeholder:text-light-50 dark:placeholder:text-dark-50 appearance-none outline-none px-3 py-1 text-5xl font-thin bg-transparent" />
|
<div class="flex gap-4 self-end xl:self-auto">
|
||||||
</div>
|
<Tooltip message="Consultable uniquement par le propriétaire" side="bottom"><Switch label="Privé" v-model="page.private" /></Tooltip>
|
||||||
<div class="flex gap-4">
|
<Tooltip message="Afficher dans le menu de navigation" side="bottom"><Switch label="Navigable" v-model="page.navigable" /></Tooltip>
|
||||||
<Tooltip message="Consultable uniquement par le propriétaire" side="bottom"><Switch label="Privé" v-model="page.private" /></Tooltip>
|
<Button @click="() => save()" :loading="saveStatus === 'pending'" class="border-light-blue dark:border-dark-blue hover:border-light-blue dark:hover:border-dark-blue focus:shadow-light-blue dark:focus:shadow-dark-blue">Enregistrer</Button>
|
||||||
<Tooltip message="Afficher dans le menu de navigation" side="bottom"><Switch label="Navigable" v-model="page.navigable" /></Tooltip>
|
|
||||||
<Button @click="() => save()" :loading="saveStatus === 'pending'" class="border-light-blue dark:border-dark-blue hover:border-light-blue dark:hover:border-dark-blue focus:shadow-light-blue dark:focus:shadow-dark-blue">Enregistrer</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="border-t border-light-35 dark:border-dark-35 mt-4 flex-1 w-full max-h-full flex pt-4">
|
|
||||||
<template v-if="page.type === 'markdown'">
|
|
||||||
<textarea v-model="page.content" class="flex-1 bg-transparent appearance-none outline-none max-h-full resize-none"></textarea>
|
|
||||||
<div class="flex-1 border-s border-light-35 dark:border-dark-35 ms-4 pt-4 ps-4 max-h-full">
|
|
||||||
<Markdown class="max-h-full overflow-auto" :content="page.content" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="page.type === 'canvas'">
|
|
||||||
<span class="flex-1 items-center"><ProseH1>Editeur de graphe en cours de développement</ProseH1></span>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="page.type === 'file'">
|
|
||||||
<span>Modifier le contenu :</span><input type="file" @change="(e) => console.log(e)" />
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="my-4 flex-1 w-full max-h-full flex">
|
||||||
|
<template v-if="page.type === 'markdown'">
|
||||||
|
<SplitterGroup direction="horizontal" class="flex-1 w-full flex">
|
||||||
|
<SplitterPanel asChild>
|
||||||
|
<textarea v-model="page.content" class="flex-1 bg-transparent appearance-none outline-none max-h-full resize-none !overflow-y-auto"></textarea>
|
||||||
|
</SplitterPanel>
|
||||||
|
<SplitterResizeHandle class="bg-light-35 dark:bg-dark-35 w-px xl!mx-4 mx-2" />
|
||||||
|
<SplitterPanel asChild>
|
||||||
|
<div class="flex-1 max-h-full !overflow-y-auto"><Markdown :content="page.content" /></div>
|
||||||
|
</SplitterPanel>
|
||||||
|
</SplitterGroup>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="page.type === 'canvas'">
|
||||||
|
<span class="flex-1 items-center"><ProseH1>Editeur de graphe en cours de développement</ProseH1></span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="page.type === 'file'">
|
||||||
|
<span>Modifier le contenu :</span><input type="file" @change="(e) => console.log(e)" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="status === 'pending'" class="flex">
|
<div v-else-if="status === 'pending'" class="flex">
|
||||||
<Head>
|
<Head>
|
||||||
|
|
@ -40,12 +43,18 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const route = useRouter().currentRoute;
|
const route = useRouter().currentRoute;
|
||||||
const path = computed(() => Array.isArray(route.value.params.path) ? route.value.params.path[0] : route.value.params.path);
|
const path = computed(() => Array.isArray(route.value.params.path) ? route.value.params.path[0] : route.value.params.path);
|
||||||
|
const { user, loggedIn } = useUserSession();
|
||||||
|
|
||||||
const toaster = useToast();
|
const toaster = useToast();
|
||||||
const saveStatus = ref<'idle' | 'pending' | 'success' | 'error'>('idle');
|
const saveStatus = ref<'idle' | 'pending' | 'success' | 'error'>('idle');
|
||||||
|
|
||||||
const { data: page, status, error } = await useLazyFetch(`/api/file/${encodeURIComponent(path.value)}`, { watch: [ route, path ]});
|
const { data: page, status, error } = await useLazyFetch(`/api/file/${encodeURIComponent(path.value)}`, { watch: [ route, path ]});
|
||||||
|
|
||||||
|
if(!loggedIn || (page.value && page.value.owner !== user.value?.id))
|
||||||
|
{
|
||||||
|
useRouter().replace({ name: 'explore-path', params: { path: path.value } });
|
||||||
|
}
|
||||||
|
|
||||||
async function save(): Promise<void>
|
async function save(): Promise<void>
|
||||||
{
|
{
|
||||||
saveStatus.value = 'pending';
|
saveStatus.value = 'pending';
|
||||||
|
|
|
||||||
|
|
@ -11,26 +11,11 @@ watch(loading, (value) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Head>
|
<Head>
|
||||||
<Title>Accueil</Title>
|
<Title>d[any] - Accueil</Title>
|
||||||
</Head>
|
</Head>
|
||||||
<div class="h-full w-full flex flex-1 flex-col justify-center items-center">
|
<div class="h-full w-full flex flex-1 flex-col justify-center items-center">
|
||||||
<div class="w-1/2 flex flex-1 flex-col justify-center items-center gap-2">
|
<Avatar src="/logo.dark.svg" class="dark:block hidden w-48 h-48" />
|
||||||
<Collapsible label="Options">
|
<Avatar src="/logo.light.svg" class="block dark:hidden w-48 h-48" />
|
||||||
<div class="flex flex-col justify-start items-start">
|
<h1 class="text-5xl font-thin font-mono">Bienvenue</h1>
|
||||||
<div class="w-full flex flex-row justify-center">
|
|
||||||
<Switch v-model="disabled" onIcon="radix-icons:lock-closed" offIcon="radix-icons:lock-open-2" />
|
|
||||||
<ThemeSwitch />
|
|
||||||
</div>
|
|
||||||
<SliderInput :disabled="disabled" :label="`Prix: ${price.toFixed(2)}€`" :min="0" :max="1500" :step="0.25"
|
|
||||||
v-model="price" />
|
|
||||||
<TextInput label="Saisir un pseudonyme" :disabled="disabled" v-model="username" />
|
|
||||||
<NumberPicker label="Age" :disabled="disabled" />
|
|
||||||
</div>
|
|
||||||
</Collapsible>
|
|
||||||
|
|
||||||
<Button :loading="loading" @click="() => loading = true">
|
|
||||||
<span v-if="!loading">Load data</span>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
<TextInput type="text" label="Utilisateur ou email" autocomplete="username" v-model="state.usernameOrEmail"/>
|
<TextInput type="text" label="Utilisateur ou email" autocomplete="username" v-model="state.usernameOrEmail"/>
|
||||||
<TextInput type="password" label="Mot de passe" autocomplete="current-password" v-model="state.password"/>
|
<TextInput type="password" label="Mot de passe" autocomplete="current-password" v-model="state.password"/>
|
||||||
<Button class="border border-light-35 dark:border-dark-35 self-center" :loading="status === 'pending'">Se connecter</Button>
|
<Button class="border border-light-35 dark:border-dark-35 self-center" :loading="status === 'pending'">Se connecter</Button>
|
||||||
<NuxtLink class="mt-4 text-center block text-sm font-semibold tracking-wide hover:text-accent-blue" :to="{ path: `/user/register`, force: true }">Pas de compte ?</NuxtLink>
|
<NuxtLink class="mt-4 text-center block text-sm font-semibold tracking-wide hover:text-accent-blue" :to="{ name: 'user-register' }">Pas de compte ?</NuxtLink>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ const deleting = ref(false);
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
</AlertDialogPortal>
|
</AlertDialogPortal>
|
||||||
</AlertDialogRoot>
|
</AlertDialogRoot>
|
||||||
<Button v-if="hasPermissions(user.permissions, ['admin'])"><NuxtLink :href="{ name: 'admin' }">Administration</NuxtLink></Button>
|
<NuxtLink v-if="hasPermissions(user.permissions, ['admin'])" :href="{ name: 'admin' }"><Button>Administration</Button></NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex" v-if="user.permissions">
|
<div class="flex" v-if="user.permissions">
|
||||||
<ProseTable class="!m-0">
|
<ProseTable class="!m-0">
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
</div>
|
</div>
|
||||||
<TextInput type="password" label="Confirmation du mot de passe" autocomplete="new-password" v-model="confirmPassword" class="w-full md:w-auto"/>
|
<TextInput type="password" label="Confirmation du mot de passe" autocomplete="new-password" v-model="confirmPassword" class="w-full md:w-auto"/>
|
||||||
<Button class="border border-light-35 dark:border-dark-35 max-w-48 w-full order-9 col-span-2 md:col-span-1 m-auto" :loading="status === 'pending'">S'inscrire</Button>
|
<Button class="border border-light-35 dark:border-dark-35 max-w-48 w-full order-9 col-span-2 md:col-span-1 m-auto" :loading="status === 'pending'">S'inscrire</Button>
|
||||||
<span class="mt-4 order-10 flex justify-center items-center gap-4 col-span-2 md:col-span-1 m-auto">Vous avez déjà un compte ?<NuxtLink class="text-center block text-sm font-semibold tracking-wide hover:text-accent-blue" :to="{ path: `/user/login`, force: true }">Se connecter</NuxtLink></span>
|
<span class="mt-4 order-10 flex justify-center items-center gap-4 col-span-2 md:col-span-1 m-auto">Vous avez déjà un compte ?<NuxtLink class="text-center block text-sm font-semibold tracking-wide hover:text-accent-blue" :to="{ name: 'user-login' }">Se connecter</NuxtLink></span>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -1,4 +1,11 @@
|
||||||
export default defineEventHandler(async (e) => {
|
export default defineEventHandler(async (e) => {
|
||||||
|
const session = await getUserSession(e);
|
||||||
|
|
||||||
|
if(!session.user || !hasPermissions(session.user.permissions, ['admin']))
|
||||||
|
{
|
||||||
|
setResponseStatus(e, 404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const id = getRouterParam(e, 'id');
|
const id = getRouterParam(e, 'id');
|
||||||
|
|
||||||
if(!id)
|
if(!id)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue