Adding prestyled base tags and testing admin dashboard
This commit is contained in:
parent
633231f821
commit
0105a6aaea
2
app.vue
2
app.vue
|
|
@ -4,7 +4,9 @@
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<ToastProvider>
|
<ToastProvider>
|
||||||
|
<div class="px-12 flex flex-1 justify-center">
|
||||||
<NuxtPage></NuxtPage>
|
<NuxtPage></NuxtPage>
|
||||||
|
</div>
|
||||||
</ToastProvider>
|
</ToastProvider>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<button class="text-light-100 dark:text-dark-100 font-semibold hover:bg-light-30 dark:hover:bg-dark-30 inline-flex items-center justify-center bg-light-25 dark:bg-dark-25 leading-none outline-none
|
<button class="text-light-100 dark:text-dark-100 font-semibold hover:bg-light-30 dark:hover:bg-dark-30 inline-flex items-center justify-center bg-light-25 dark:bg-dark-25 leading-none outline-none
|
||||||
border border-light-25 dark:border-dark-25 hover:border-light-30 dark:hover:border-dark-30 active:border-light-40 dark:active:border-dark-40 focus:shadow-raw transition-[box-shadow] focus:shadow-light-40 dark:focus:shadow-dark-40"
|
border border-light-25 dark:border-dark-25 hover:border-light-30 dark:hover:border-dark-30 active:border-light-40 dark:active:border-dark-40 focus:shadow-raw transition-[box-shadow] focus:shadow-light-40 dark:focus:shadow-dark-40"
|
||||||
:class="{'p-1': icon, 'h-[35px] px-[15px]': !icon}" >
|
:class="{'p-1': loading || icon, 'h-[35px] px-[15px]': !loading && !icon}" @click="!loading && emit('click')">
|
||||||
<slot />
|
<Loading v-if="loading" />
|
||||||
|
<slot v-else />
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { icon = false } = defineProps<{
|
const { icon = false, loading = false } = defineProps<{
|
||||||
icon?: boolean
|
icon?: boolean
|
||||||
|
loading?: boolean
|
||||||
}>();
|
}>();
|
||||||
|
const emit = defineEmits(['click']);
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Label>{{ label }}
|
<Label class="py-4 flex flex-row justify-center items-center">
|
||||||
<SelectRoot :v-model="model">
|
<span>{{ label }}</span>
|
||||||
|
<SelectRoot v-model="model">
|
||||||
<SelectTrigger :disabled="disabled" class="mx-4 inline-flex min-w-[160px] items-center justify-between px-3 text-sm font-semibold leading-none h-8 gap-1
|
<SelectTrigger :disabled="disabled" class="mx-4 inline-flex min-w-[160px] items-center justify-between px-3 text-sm font-semibold leading-none h-8 gap-1
|
||||||
bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 outline-none data-[placeholder]:font-normal
|
bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 outline-none data-[placeholder]:font-normal
|
||||||
data-[placeholder]:text-light-50 dark:data-[placeholder]:text-dark-50 focus:shadow-raw transition-[box-shadow] focus:shadow-light-40 dark:focus:shadow-dark-40
|
data-[placeholder]:text-light-50 dark:data-[placeholder]:text-dark-50 focus:shadow-raw transition-[box-shadow] focus:shadow-light-40 dark:focus:shadow-dark-40
|
||||||
|
|
@ -15,7 +16,7 @@
|
||||||
<SelectScrollUpButton>
|
<SelectScrollUpButton>
|
||||||
<Icon icon="radix-icons:chevron-up" />
|
<Icon icon="radix-icons:chevron-up" />
|
||||||
</SelectScrollUpButton>
|
</SelectScrollUpButton>
|
||||||
<SelectViewport class="p-1">
|
<SelectViewport>
|
||||||
<slot />
|
<slot />
|
||||||
</SelectViewport>
|
</SelectViewport>
|
||||||
<SelectScrollDownButton>
|
<SelectScrollDownButton>
|
||||||
|
|
@ -28,6 +29,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { SelectContent, SelectPortal, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectTrigger, SelectValue, SelectViewport } from 'radix-vue'
|
||||||
import { Icon } from '@iconify/vue/dist/iconify.js';
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||||
const { placeholder, disabled = false, position = 'popper', label } = defineProps<{
|
const { placeholder, disabled = false, position = 'popper', label } = defineProps<{
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
|
|
@ -35,5 +37,5 @@ const { placeholder, disabled = false, position = 'popper', label } = defineProp
|
||||||
position?: 'item-aligned' | 'popper'
|
position?: 'item-aligned' | 'popper'
|
||||||
label?: string
|
label?: string
|
||||||
}>();
|
}>();
|
||||||
const model = defineModel();
|
const model = defineModel<string>();
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<SelectItem :value="value" :disabled="disabled" class="">
|
<SelectItem :value="value" :disabled="disabled" class="text-base py-2 leading-none text-light-60 dark:text-dark-60 flex items-center px-6 relative select-none data-[disabled]:text-light-50 dark:data-[disabled]:text-dark-50 data-[disabled]:pointer-events-none data-[highlighted]:outline-none data-[highlighted]:bg-light-30 dark:data-[highlighted]:bg-dark-30 data-[highlighted]:text-light-100 dark:data-[highlighted]:text-dark-100">
|
||||||
<SelectItemText class="">{{ label }}</SelectItemText>
|
<SelectItemText class="">{{ label }}</SelectItemText>
|
||||||
<SelectItemIndicator class="">
|
<SelectItemIndicator class="absolute left-1 w-4 inline-flex items-center justify-center">
|
||||||
<Icon icon="radix-icons:check" />
|
<Icon icon="radix-icons:check" />
|
||||||
</SelectItemIndicator>
|
</SelectItemIndicator>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Icon } from '@iconify/vue/dist/iconify.js';
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||||
import { SelectItem } from 'radix-vue';
|
import { SelectItem, SelectItemIndicator, SelectItemText } from 'radix-vue'
|
||||||
const { disabled = false, value } = defineProps<{
|
const { disabled = false, value } = defineProps<{
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
value: NonNullable<any>
|
value: NonNullable<any>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ToastRoot :duration="duration" class="ToastRoot bg-light-10 dark:bg-dark-10 border border-light-30 dark:border-dark-30" v-model:open="model">
|
<ToastRoot :default-open="open" :duration="duration" class="ToastRoot bg-light-10 dark:bg-dark-10 border border-light-30 dark:border-dark-30" v-model:open="model">
|
||||||
<div class="grid grid-cols-8 p-3">
|
<div class="grid grid-cols-8 p-3">
|
||||||
<ToastTitle v-if="title" class="font-semibold text-xl col-span-7 text-light-70 dark:text-dark-70" asChild><h4>{{ title }}</h4></ToastTitle>
|
<ToastTitle v-if="title" class="font-semibold text-xl col-span-7 text-light-70 dark:text-dark-70" asChild><h4>{{ title }}</h4></ToastTitle>
|
||||||
<ToastClose v-if="closeable" aria-label="Close" class="text-2xl -translate-y-1/2 translate-x-1/2 cursor-pointer"><span aria-hidden>×</span></ToastClose>
|
<ToastClose v-if="closeable" aria-label="Close" class="text-2xl -translate-y-1/2 translate-x-1/2 cursor-pointer"><span aria-hidden>×</span></ToastClose>
|
||||||
|
|
@ -20,6 +20,7 @@ const { closeable = true, duration, title, content, timer = true } = defineProps
|
||||||
title?: string
|
title?: string
|
||||||
content?: string
|
content?: string
|
||||||
timer?: boolean
|
timer?: boolean
|
||||||
|
open?: boolean
|
||||||
}>();
|
}>();
|
||||||
const timeout = ref<NodeJS.Timeout>();
|
const timeout = ref<NodeJS.Timeout>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<template>
|
||||||
|
<slot v-bind="$attrs"></slot>
|
||||||
|
<!-- <Suspense suspensible>
|
||||||
|
<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">
|
||||||
|
<PreviewContent :project="project" :path="data[0].path" :anchor="hash">
|
||||||
|
<template #default>
|
||||||
|
<slot v-bind="$attrs"></slot>
|
||||||
|
<Icon class="w-4 h-4 inline-block" v-if="data && data[0] && data[0].type !== 'Markdown'" :height="20" :width="20"
|
||||||
|
:icon="`icons/link-${data[0].type.toLowerCase()}`" />
|
||||||
|
</template>
|
||||||
|
</PreviewContent>
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink no-prefetch v-else-if="href" :to="href" :class="class" class="text-accent-blue inline-flex items-center">
|
||||||
|
<slot v-bind="$attrs"></slot>
|
||||||
|
<Icon class="w-4 h-4 inline-block" v-if="data && data[0] && data[0].type !== 'Markdown'" :height="20" :width="20"
|
||||||
|
:icon="`icons/link-${data[0].type.toLowerCase()}`" />
|
||||||
|
</NuxtLink>
|
||||||
|
<slot :class="class" v-else v-bind="$attrs"></slot>
|
||||||
|
</Suspense> -->
|
||||||
|
</template>
|
||||||
|
<!--<script setup lang="ts">
|
||||||
|
import { parseURL } from 'ufo';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
href: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { hash, pathname, protocol } = parseURL(props.href);
|
||||||
|
const project = computed(() => parseInt(Array.isArray(route.params.projectId) ? '0' : route.params.projectId));
|
||||||
|
const data = ref();
|
||||||
|
|
||||||
|
if(!!pathname && !protocol)
|
||||||
|
{
|
||||||
|
data.value = await $fetch(`/api/project/${project.value}/file`, {
|
||||||
|
query: {
|
||||||
|
search: `%${pathname}`
|
||||||
|
},
|
||||||
|
ignoreResponseError: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>-->
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
<template>
|
||||||
|
<blockquote ref="el">
|
||||||
|
<slot />
|
||||||
|
</blockquote>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- <script setup lang="ts">
|
||||||
|
const attrs = useAttrs(), el = ref<HTMLQuoteElement>(), title = ref<Element | null>(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if(el && el.value && attrs.hasOwnProperty("dataCalloutFold"))
|
||||||
|
{
|
||||||
|
title.value = el.value.querySelector('.callout-title');
|
||||||
|
title.value?.addEventListener('click', toggle);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
title.value?.removeEventListener('click', toggle);
|
||||||
|
})
|
||||||
|
function toggle() {
|
||||||
|
el.value?.classList?.toggle('is-collapsed');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
blockquote:not(.callout)
|
||||||
|
{
|
||||||
|
@apply ps-4;
|
||||||
|
@apply my-4;
|
||||||
|
@apply relative;
|
||||||
|
@apply before:absolute;
|
||||||
|
@apply before:-top-1;
|
||||||
|
@apply before:-bottom-1;
|
||||||
|
@apply before:left-0;
|
||||||
|
@apply before:w-1;
|
||||||
|
@apply before:bg-light-30;
|
||||||
|
@apply dark:before:bg-dark-30;
|
||||||
|
}
|
||||||
|
blockquote:empty
|
||||||
|
{
|
||||||
|
@apply before:hidden;
|
||||||
|
}
|
||||||
|
.callout {
|
||||||
|
@apply bg-light-blue;
|
||||||
|
@apply dark:bg-dark-blue;
|
||||||
|
}
|
||||||
|
.callout.is-collapsible .callout-title
|
||||||
|
{
|
||||||
|
@apply cursor-pointer;
|
||||||
|
}
|
||||||
|
.callout .fold
|
||||||
|
{
|
||||||
|
@apply transition-transform;
|
||||||
|
}
|
||||||
|
.callout.is-collapsed .fold
|
||||||
|
{
|
||||||
|
@apply -rotate-90;
|
||||||
|
}
|
||||||
|
.callout.is-collapsed > p
|
||||||
|
{
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
.callout[datacallout="abstract"],
|
||||||
|
.callout[datacallout="summary"],
|
||||||
|
.callout[datacallout="tldr"] {
|
||||||
|
@apply bg-light-cyan;
|
||||||
|
@apply dark:bg-dark-cyan;
|
||||||
|
@apply text-light-cyan;
|
||||||
|
@apply dark:text-dark-cyan;
|
||||||
|
}
|
||||||
|
.callout[datacallout="info"] {
|
||||||
|
@apply bg-light-blue;
|
||||||
|
@apply dark:bg-dark-blue;
|
||||||
|
@apply text-light-blue;
|
||||||
|
@apply dark:text-dark-blue;
|
||||||
|
}
|
||||||
|
.callout[datacallout="todo"] {
|
||||||
|
@apply bg-light-blue;
|
||||||
|
@apply dark:bg-dark-blue;
|
||||||
|
@apply text-light-blue;
|
||||||
|
@apply dark:text-dark-blue;
|
||||||
|
}
|
||||||
|
.callout[datacallout="important"] {
|
||||||
|
@apply bg-light-cyan;
|
||||||
|
@apply dark:bg-dark-cyan;
|
||||||
|
@apply text-light-cyan;
|
||||||
|
@apply dark:text-dark-cyan;
|
||||||
|
}
|
||||||
|
.callout[datacallout="tip"],
|
||||||
|
.callout[datacallout="hint"] {
|
||||||
|
@apply bg-light-cyan;
|
||||||
|
@apply dark:bg-dark-cyan;
|
||||||
|
@apply text-light-cyan;
|
||||||
|
@apply dark:text-dark-cyan;
|
||||||
|
}
|
||||||
|
.callout[datacallout="success"],
|
||||||
|
.callout[datacallout="check"],
|
||||||
|
.callout[datacallout="done"] {
|
||||||
|
@apply bg-light-green;
|
||||||
|
@apply dark:bg-dark-green;
|
||||||
|
@apply text-light-green;
|
||||||
|
@apply dark:text-dark-green;
|
||||||
|
}
|
||||||
|
.callout[datacallout="question"],
|
||||||
|
.callout[datacallout="help"],
|
||||||
|
.callout[datacallout="faq"] {
|
||||||
|
@apply bg-light-orange;
|
||||||
|
@apply dark:bg-dark-orange;
|
||||||
|
@apply text-light-orange;
|
||||||
|
@apply dark:text-dark-orange;
|
||||||
|
}
|
||||||
|
.callout[datacallout="warning"],
|
||||||
|
.callout[datacallout="caution"],
|
||||||
|
.callout[datacallout="attention"] {
|
||||||
|
@apply bg-light-orange;
|
||||||
|
@apply dark:bg-dark-orange;
|
||||||
|
@apply text-light-orange;
|
||||||
|
@apply dark:text-dark-orange;
|
||||||
|
}
|
||||||
|
.callout[datacallout="failure"],
|
||||||
|
.callout[datacallout="fail"],
|
||||||
|
.callout[datacallout="missing"] {
|
||||||
|
@apply bg-light-red;
|
||||||
|
@apply dark:bg-dark-red;
|
||||||
|
@apply text-light-red;
|
||||||
|
@apply dark:text-dark-red;
|
||||||
|
}
|
||||||
|
.callout[datacallout="danger"],
|
||||||
|
.callout[datacallout="error"] {
|
||||||
|
@apply bg-light-red;
|
||||||
|
@apply dark:bg-dark-red;
|
||||||
|
@apply text-light-red;
|
||||||
|
@apply dark:text-dark-red;
|
||||||
|
}
|
||||||
|
.callout[datacallout="bug"] {
|
||||||
|
@apply bg-light-red;
|
||||||
|
@apply dark:bg-dark-red;
|
||||||
|
@apply text-light-red;
|
||||||
|
@apply dark:text-dark-red;
|
||||||
|
}
|
||||||
|
.callout[datacallout="example"] {
|
||||||
|
@apply bg-light-purple;
|
||||||
|
@apply dark:bg-dark-purple;
|
||||||
|
@apply text-light-purple;
|
||||||
|
@apply dark:text-dark-purple;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout
|
||||||
|
{
|
||||||
|
@apply overflow-hidden;
|
||||||
|
@apply my-4;
|
||||||
|
@apply p-3;
|
||||||
|
@apply ps-6;
|
||||||
|
@apply bg-blend-lighten;
|
||||||
|
@apply !bg-opacity-25;
|
||||||
|
@apply border-l-4;
|
||||||
|
@apply inline-block;
|
||||||
|
@apply pe-8;
|
||||||
|
}
|
||||||
|
.callout-icon
|
||||||
|
{
|
||||||
|
@apply w-6;
|
||||||
|
@apply h-6;
|
||||||
|
@apply stroke-2;
|
||||||
|
}
|
||||||
|
.callout-title
|
||||||
|
{
|
||||||
|
@apply flex;
|
||||||
|
@apply items-center;
|
||||||
|
@apply gap-2;
|
||||||
|
}
|
||||||
|
.callout-title-inner
|
||||||
|
{
|
||||||
|
@apply inline-block;
|
||||||
|
@apply font-bold;
|
||||||
|
}
|
||||||
|
.callout > p
|
||||||
|
{
|
||||||
|
@apply mt-2;
|
||||||
|
@apply font-semibold;
|
||||||
|
}
|
||||||
|
</style> -->
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<template>
|
||||||
|
<code><slot /></code>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<em>
|
||||||
|
<slot />
|
||||||
|
</em>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<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">
|
||||||
|
<slot />
|
||||||
|
</h1>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{ id?: string }>()
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<h2 :id="parseId(id)" class="text-4xl font-semibold mt-3 mb-6 ms-1 first:pt-0 pt-2 relative sm:right-8 right-4">
|
||||||
|
<slot />
|
||||||
|
</h2>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{ id?: string }>()
|
||||||
|
|
||||||
|
const generate = computed(() => props.id)
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<h3 :id="parseId(id)" class="text-2xl font-bold mt-2 mb-4">
|
||||||
|
<slot />
|
||||||
|
</h3>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{ id?: string }>()
|
||||||
|
|
||||||
|
const generate = computed(() => props.id)
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<template>
|
||||||
|
<h4 :id="parseId(id)" class="text-xl font-semibold my-2" style="font-variant: small-caps;">
|
||||||
|
<slot />
|
||||||
|
</h4>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{ id?: string }>()
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<h5 :id="parseId(id)" class="text-lg font-semibold my-1">
|
||||||
|
<slot />
|
||||||
|
</h5>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{ id?: string }>()
|
||||||
|
|
||||||
|
const generate = computed(() => props.id)
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<h6 :id="parseId(id)">
|
||||||
|
<slot />
|
||||||
|
</h6>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{ id?: string }>()
|
||||||
|
|
||||||
|
const generate = computed(() => props.id)
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<template>
|
||||||
|
<Separator class="border-light-35 dark:border-dark-35 m-4" />
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<img
|
||||||
|
:src="refinedSrc"
|
||||||
|
:alt="alt"
|
||||||
|
:width="width"
|
||||||
|
:height="height"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { withTrailingSlash, withLeadingSlash, joinURL } from 'ufo'
|
||||||
|
import { useRuntimeConfig, computed, resolveComponent } from '#imports'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
alt: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const refinedSrc = computed(() => {
|
||||||
|
if (props.src?.startsWith('/') && !props.src.startsWith('//')) {
|
||||||
|
const _base = withLeadingSlash(withTrailingSlash(useRuntimeConfig().app.baseURL))
|
||||||
|
if (_base !== '/' && !props.src.startsWith(_base)) {
|
||||||
|
return joinURL(_base, props.src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return props.src
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<template>
|
||||||
|
<li class="before:absolute before:top-2 before:left-0 before:inline-block before:w-2 before:h-2 before:rounded before:bg-light-40 dark:before:bg-dark-40 relative ps-4"><slot /></li>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<ol>
|
||||||
|
<slot />
|
||||||
|
</ol>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<template>
|
||||||
|
<p><slot /></p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.text-comment
|
||||||
|
{
|
||||||
|
@apply text-light-50;
|
||||||
|
@apply dark:text-dark-50;
|
||||||
|
@apply text-sm;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<template>
|
||||||
|
<pre :class="$props.class"><slot /></pre>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps({
|
||||||
|
code: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
filename: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
highlights: {
|
||||||
|
type: Array as () => number[],
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
pre code .line{display:block}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="isDev">
|
||||||
|
Rendering the <code>script</code> element is dangerous and is disabled by default. Consider implementing your own <code>ProseScript</code> element to have control over script rendering.
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps({
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const isDev = import.meta.dev
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<strong>
|
||||||
|
<slot />
|
||||||
|
</strong>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<table class="mx-4 my-8 border-collapse border border-light-35 dark:border-dark-35">
|
||||||
|
<slot />
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<!-- <HoverPopup @before-show="fetch">
|
||||||
|
<template #content>
|
||||||
|
<Suspense suspensible>
|
||||||
|
<div class="mw-[400px]">
|
||||||
|
<div v-if="fetched === false" class="loading w-[400px] h-[150px]"></div>
|
||||||
|
<template v-else-if="!!data">
|
||||||
|
<div v-if="data.description" class="pb-4 pt-3 px-8">
|
||||||
|
<span class="text-2xl font-semibold">#{{ data.tag }}</span>
|
||||||
|
<Markdown :content="data.description"></Markdown>
|
||||||
|
</div>
|
||||||
|
<div class="h-100 w-100 flex flex-1 flex-col justify-center items-center" v-else>
|
||||||
|
<div class="text-3xl font-extralight tracking-wide text-light-60 dark:text-dark-60">Fichier vide</div>
|
||||||
|
<div class="text-lg text-light-60 dark:text-dark-60">Cette page est vide</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="h-100 w-100 flex flex-1 flex-col justify-center items-center" v-else>
|
||||||
|
<div class="text-3xl font-extralight tracking-wide text-light-60 dark:text-dark-60">Impossible d'afficher</div>
|
||||||
|
<div class="text-lg text-light-60 dark:text-dark-60">Cette page est impossible à traiter</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #fallback><div class="loading w-[400px] h-[150px]"></div></template>
|
||||||
|
</Suspense>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<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>
|
||||||
|
</HoverPopup> -->
|
||||||
|
<slot />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- <script setup lang="ts">
|
||||||
|
import type { Tag } from '~/types/api';
|
||||||
|
|
||||||
|
const { tag } = defineProps({
|
||||||
|
tag: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = ref<Tag>(), fetched = ref(false);
|
||||||
|
const route = useRoute();
|
||||||
|
const project = computed(() => parseInt(Array.isArray(route.params.projectId) ? '0' : route.params.projectId));
|
||||||
|
async function fetch()
|
||||||
|
{
|
||||||
|
if(fetched.value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data.value = await $fetch(`/api/project/${project.value}/tags/${encodeURIComponent(tag)}`);
|
||||||
|
fetched.value = true;
|
||||||
|
}
|
||||||
|
</script> -->
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<tbody>
|
||||||
|
<slot />
|
||||||
|
</tbody>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<td class="border border-light-35 dark:border-dark-35 py-1 px-2">
|
||||||
|
<slot />
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<th class="border border-light-35 dark:border-dark-35 px-4 first:pt-0">
|
||||||
|
<slot />
|
||||||
|
</th>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<thead>
|
||||||
|
<slot />
|
||||||
|
</thead>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<tr>
|
||||||
|
<slot />
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<ul>
|
||||||
|
<slot />
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
@ -69,7 +69,7 @@ export default defineNuxtConfig({
|
||||||
50: "#ababab",
|
50: "#ababab",
|
||||||
60: "#707070",
|
60: "#707070",
|
||||||
70: "#5c5c5c",
|
70: "#5c5c5c",
|
||||||
100: "#222222",
|
100: "#202020",
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
red: '#fb464c',
|
red: '#fb464c',
|
||||||
|
|
@ -111,6 +111,11 @@ export default defineNuxtConfig({
|
||||||
pathPrefix: false,
|
pathPrefix: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
nitro: {
|
||||||
|
experimental: {
|
||||||
|
tasks: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
security: {
|
security: {
|
||||||
rateLimiter: false,
|
rateLimiter: false,
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,50 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const job = ref<string>('');
|
||||||
|
|
||||||
|
const data = ref(), status = ref<'idle' | 'pending' | 'success' | 'error'>('idle'), success = ref(false), err = ref(false), error = ref();
|
||||||
|
async function fetch()
|
||||||
|
{
|
||||||
|
status.value = 'pending';
|
||||||
|
data.value = null;
|
||||||
|
error.value = null;
|
||||||
|
err.value = false;
|
||||||
|
success.value = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
data.value = await $fetch(`/api/admin/jobs/${job.value}`, {
|
||||||
|
method: 'POST',
|
||||||
|
});
|
||||||
|
status.value = 'success';
|
||||||
|
error.value = null;
|
||||||
|
err.value = false;
|
||||||
|
success.value = true;
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
status.value = 'error';
|
||||||
|
error.value = e;
|
||||||
|
err.value = true;
|
||||||
|
success.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
Administration
|
<Head>
|
||||||
|
<Title>Administration</Title>
|
||||||
|
</Head>
|
||||||
|
<div class="flex flex-col justify-start">
|
||||||
|
<ProseH2>Administration</ProseH2>
|
||||||
|
<Select label="Job" v-model="job">
|
||||||
|
<SelectItem label="Synchroniser" value="sync" />
|
||||||
|
<SelectItem label="Nettoyer la base" value="clear" />
|
||||||
|
<SelectItem label="Reconstruire" value="rebuild" disabled />
|
||||||
|
</Select>
|
||||||
|
<Button class="self-center" @click="() => !!job && fetch()" :loading="status === 'pending'">
|
||||||
|
<span>Executer</span>
|
||||||
|
</Button>
|
||||||
|
<Toast :duration="10000" title="Erreur" :content="error?.message" v-model="err" />
|
||||||
|
<Toast :duration="10000" content="Traitement terminé" v-model="success" :closeable="false" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -13,11 +13,11 @@ watch(loading, (value) => {
|
||||||
<Head>
|
<Head>
|
||||||
<Title>Accueil</Title>
|
<Title>Accueil</Title>
|
||||||
</Head>
|
</Head>
|
||||||
<div class="h-100 w-100 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">
|
<div class="w-1/2 flex flex-1 flex-col justify-center items-center gap-2">
|
||||||
<Collapsible label="Options">
|
<Collapsible label="Options">
|
||||||
<div class="flex flex-col justify-start items-start">
|
<div class="flex flex-col justify-start items-start">
|
||||||
<div class="flex flex-row">
|
<div class="w-full flex flex-row justify-center">
|
||||||
<Switch v-model="disabled" onIcon="radix-icons:lock-closed" offIcon="radix-icons:lock-open-2" />
|
<Switch v-model="disabled" onIcon="radix-icons:lock-closed" offIcon="radix-icons:lock-open-2" />
|
||||||
<ThemeSwitch />
|
<ThemeSwitch />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -28,9 +28,8 @@ watch(loading, (value) => {
|
||||||
</div>
|
</div>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
|
|
||||||
<Button @click="() => loading = true">
|
<Button :loading="loading" @click="() => loading = true">
|
||||||
<span v-if="!loading">Load data</span>
|
<span v-if="!loading">Load data</span>
|
||||||
<Loading v-else size="small" />
|
|
||||||
</Button>
|
</Button>
|
||||||
<Toast v-model="open" :duration="7500" content="Je suis un long texte pour tester comment ça se comporte aaaaaaaa aaaaaaaa aaaaaaaaa aaaaaaaa" :closeable="false" />
|
<Toast v-model="open" :duration="7500" content="Je suis un long texte pour tester comment ça se comporte aaaaaaaa aaaaaaaa aaaaaaaaa aaaaaaaa" :closeable="false" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
export default defineEventHandler(async (e) => {
|
||||||
|
const id = getRouterParam(e, 'id');
|
||||||
|
|
||||||
|
if(!id)
|
||||||
|
{
|
||||||
|
setResponseStatus(e, 400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await runTask(id);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
export function unifySlug(slug: string | string[]): string
|
||||||
|
{
|
||||||
|
return (Array.isArray(slug) ? slug.join('/') : slug);
|
||||||
|
}
|
||||||
|
export function parseId(id: string | undefined): string |undefined
|
||||||
|
{
|
||||||
|
return id?.normalize('NFD')?.replace(/[\u0300-\u036f]/g, '')?.replace(/^\d\. */g, '')?.replace(/\s/g, "-")?.replace(/%/g, "-percent")?.replace(/\?/g, "-q")?.toLowerCase();
|
||||||
|
}
|
||||||
|
export function padLeft(text: string, pad: string, length: number): string
|
||||||
|
{
|
||||||
|
return text.concat(pad.repeat(length - text.length));
|
||||||
|
}
|
||||||
|
export function padRight(text: string, pad: string, length: number): string
|
||||||
|
{
|
||||||
|
return pad.repeat(length - text.length).concat(text);
|
||||||
|
}
|
||||||
|
export function format(date: Date, template: string): string
|
||||||
|
{
|
||||||
|
const transforms: Record<string, (date: Date) => string> = {
|
||||||
|
"yyyy": (date: Date) => date.getUTCFullYear().toString(),
|
||||||
|
"MM": (date: Date) => padRight((date.getUTCMonth() + 1).toString(), '0', 2),
|
||||||
|
"dd": (date: Date) => padRight(date.getUTCDate().toString(), '0', 2),
|
||||||
|
"mm": (date: Date) => padRight(date.getFullYear().toString(), '0', 2),
|
||||||
|
"HH": (date: Date) => padRight(date.getFullYear().toString(), '0', 2),
|
||||||
|
"ss": (date: Date) => padRight(date.getFullYear().toString(), '0', 2),
|
||||||
|
};
|
||||||
|
const keys = Object.keys(transforms);
|
||||||
|
|
||||||
|
for(const key of keys)
|
||||||
|
{
|
||||||
|
template = template.replaceAll(key, () => transforms[key](date));
|
||||||
|
}
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
export function clamp(x: number, min: number, max: number): number {
|
||||||
|
if (x > max)
|
||||||
|
return max;
|
||||||
|
if (x < min)
|
||||||
|
return min;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue