chore: format
This commit is contained in:
@@ -1,58 +1,63 @@
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
colors: {
|
||||
primary: 'emerald',
|
||||
secondary: 'fuchsia',
|
||||
neutral: 'zinc'
|
||||
},
|
||||
footer: {
|
||||
slots: {
|
||||
root: 'border-t border-default',
|
||||
left: 'text-sm text-muted'
|
||||
}
|
||||
}
|
||||
},
|
||||
seo: {
|
||||
siteName: 'Kompose'
|
||||
},
|
||||
header: {
|
||||
title: '',
|
||||
to: '/',
|
||||
logo: {
|
||||
alt: '',
|
||||
light: '',
|
||||
dark: ''
|
||||
},
|
||||
search: true,
|
||||
colorMode: true,
|
||||
links: [{
|
||||
'icon': 'i-simple-icons-github',
|
||||
'to': 'https://github.com/nuxt-ui-templates/docs',
|
||||
'target': '_blank',
|
||||
'aria-label': 'GitHub'
|
||||
}]
|
||||
},
|
||||
footer: {
|
||||
credits: `kompose © Valknar ${new Date().getFullYear()}`,
|
||||
colorMode: false,
|
||||
links: [{
|
||||
'icon': 'i-simple-icons-x',
|
||||
'to': 'https://x.com/bordeaux1981',
|
||||
'target': '_blank',
|
||||
'aria-label': 'Nuxt on X'
|
||||
}, {
|
||||
'icon': 'i-simple-icons-github',
|
||||
'to': 'https://github.com/valknarogg',
|
||||
'target': '_blank',
|
||||
'aria-label': 'Valknar on GitHub'
|
||||
}]
|
||||
},
|
||||
toc: {
|
||||
title: 'Table of Contents',
|
||||
bottom: {
|
||||
title: 'Community',
|
||||
edit: 'https://code.pivoine.art/valknar/kompose/src/branch/main/docs/content',
|
||||
links: []
|
||||
}
|
||||
}
|
||||
})
|
||||
ui: {
|
||||
colors: {
|
||||
primary: "emerald",
|
||||
secondary: "fuchsia",
|
||||
neutral: "zinc",
|
||||
},
|
||||
footer: {
|
||||
slots: {
|
||||
root: "border-t border-default",
|
||||
left: "text-sm text-muted",
|
||||
},
|
||||
},
|
||||
},
|
||||
seo: {
|
||||
siteName: "Kompose",
|
||||
},
|
||||
header: {
|
||||
title: "",
|
||||
to: "/",
|
||||
logo: {
|
||||
alt: "",
|
||||
light: "",
|
||||
dark: "",
|
||||
},
|
||||
search: true,
|
||||
colorMode: true,
|
||||
links: [
|
||||
{
|
||||
icon: "i-simple-icons-github",
|
||||
to: "https://github.com/nuxt-ui-templates/docs",
|
||||
target: "_blank",
|
||||
"aria-label": "GitHub",
|
||||
},
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
credits: `kompose © Valknar ${new Date().getFullYear()}`,
|
||||
colorMode: false,
|
||||
links: [
|
||||
{
|
||||
icon: "i-simple-icons-x",
|
||||
to: "https://x.com/bordeaux1981",
|
||||
target: "_blank",
|
||||
"aria-label": "Nuxt on X",
|
||||
},
|
||||
{
|
||||
icon: "i-simple-icons-github",
|
||||
to: "https://github.com/valknarogg",
|
||||
target: "_blank",
|
||||
"aria-label": "Valknar on GitHub",
|
||||
},
|
||||
],
|
||||
},
|
||||
toc: {
|
||||
title: "Table of Contents",
|
||||
bottom: {
|
||||
title: "Community",
|
||||
edit: "https://code.pivoine.art/valknar/kompose/src/branch/main/docs/content",
|
||||
links: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
const { seo } = useAppConfig()
|
||||
const { seo } = useAppConfig();
|
||||
|
||||
const { data: navigation } = await useAsyncData('navigation', () => queryCollectionNavigation('docs'))
|
||||
const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSections('docs'), {
|
||||
server: false
|
||||
})
|
||||
const { data: navigation } = await useAsyncData("navigation", () =>
|
||||
queryCollectionNavigation("docs"),
|
||||
);
|
||||
const { data: files } = useLazyAsyncData(
|
||||
"search",
|
||||
() => queryCollectionSearchSections("docs"),
|
||||
{
|
||||
server: false,
|
||||
},
|
||||
);
|
||||
|
||||
useHead({
|
||||
meta: [
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
||||
],
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
}
|
||||
})
|
||||
meta: [{ name: "viewport", content: "width=device-width, initial-scale=1" }],
|
||||
htmlAttrs: {
|
||||
lang: "en",
|
||||
},
|
||||
});
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: `%s - ${seo?.siteName}`,
|
||||
ogSiteName: seo?.siteName,
|
||||
twitterCard: 'summary_large_image'
|
||||
})
|
||||
titleTemplate: `%s - ${seo?.siteName}`,
|
||||
ogSiteName: seo?.siteName,
|
||||
twitterCard: "summary_large_image",
|
||||
});
|
||||
|
||||
provide('navigation', navigation)
|
||||
provide("navigation", navigation);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -4,30 +4,30 @@
|
||||
@source "../../../content/**/*";
|
||||
|
||||
@theme static {
|
||||
--container-8xl: 90rem;
|
||||
--font-sans: 'Public Sans', sans-serif;
|
||||
--container-8xl: 90rem;
|
||||
--font-sans: "Public Sans", sans-serif;
|
||||
|
||||
--color-green-50: #EFFDF5;
|
||||
--color-green-100: #D9FBE8;
|
||||
--color-green-200: #B3F5D1;
|
||||
--color-green-300: #75EDAE;
|
||||
--color-green-400: #00DC82;
|
||||
--color-green-500: #00C16A;
|
||||
--color-green-600: #00A155;
|
||||
--color-green-700: #007F45;
|
||||
--color-green-800: #016538;
|
||||
--color-green-900: #0A5331;
|
||||
--color-green-950: #052E16;
|
||||
--color-green-50: #effdf5;
|
||||
--color-green-100: #d9fbe8;
|
||||
--color-green-200: #b3f5d1;
|
||||
--color-green-300: #75edae;
|
||||
--color-green-400: #00dc82;
|
||||
--color-green-500: #00c16a;
|
||||
--color-green-600: #00a155;
|
||||
--color-green-700: #007f45;
|
||||
--color-green-800: #016538;
|
||||
--color-green-900: #0a5331;
|
||||
--color-green-950: #052e16;
|
||||
}
|
||||
|
||||
:root {
|
||||
--ui-container: var(--container-8xl);
|
||||
--ui-container: var(--container-8xl);
|
||||
}
|
||||
|
||||
h2 > a > span + span {
|
||||
@apply size-6 align-text-top;
|
||||
@apply size-6 align-text-top;
|
||||
}
|
||||
|
||||
h3 > a > span + span {
|
||||
@apply size-5 align-text-top;
|
||||
@apply size-5 align-text-top;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
const { footer } = useAppConfig()
|
||||
const { footer } = useAppConfig();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { ContentNavigationItem } from '@nuxt/content'
|
||||
import type { ContentNavigationItem } from "@nuxt/content";
|
||||
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>("navigation");
|
||||
|
||||
const { header } = useAppConfig()
|
||||
const { header } = useAppConfig();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -75,50 +75,50 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref } from "vue";
|
||||
|
||||
interface Props {
|
||||
size?: string
|
||||
interactive?: boolean
|
||||
size?: string;
|
||||
interactive?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: '192px',
|
||||
interactive: true
|
||||
})
|
||||
size: "192px",
|
||||
interactive: true,
|
||||
});
|
||||
|
||||
const isClicked = ref(false)
|
||||
const showRipple = ref(false)
|
||||
const isClicked = ref(false);
|
||||
const showRipple = ref(false);
|
||||
|
||||
const handleClick = () => {
|
||||
if (!props.interactive) return
|
||||
if (!props.interactive) return;
|
||||
|
||||
isClicked.value = true
|
||||
showRipple.value = true
|
||||
isClicked.value = true;
|
||||
showRipple.value = true;
|
||||
|
||||
setTimeout(() => {
|
||||
isClicked.value = false
|
||||
}, 600)
|
||||
setTimeout(() => {
|
||||
isClicked.value = false;
|
||||
}, 600);
|
||||
|
||||
setTimeout(() => {
|
||||
showRipple.value = false
|
||||
}, 800)
|
||||
}
|
||||
setTimeout(() => {
|
||||
showRipple.value = false;
|
||||
}, 800);
|
||||
};
|
||||
|
||||
const handleHover = () => {
|
||||
if (!props.interactive) return
|
||||
// Hover animations are handled by CSS
|
||||
}
|
||||
if (!props.interactive) return;
|
||||
// Hover animations are handled by CSS
|
||||
};
|
||||
|
||||
const handleLeave = () => {
|
||||
if (!props.interactive) return
|
||||
// Leave animations are handled by CSS
|
||||
}
|
||||
if (!props.interactive) return;
|
||||
// Leave animations are handled by CSS
|
||||
};
|
||||
|
||||
const handleTouch = (e: TouchEvent) => {
|
||||
if (!props.interactive) return
|
||||
handleClick()
|
||||
}
|
||||
if (!props.interactive) return;
|
||||
handleClick();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
import AppIcon from './AppIcon.vue'
|
||||
import AppIcon from "./AppIcon.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
size: {
|
||||
type: String,
|
||||
default: '42px' // Can be: '24px', '32px', '42px', '56px', etc.
|
||||
}
|
||||
})
|
||||
size: {
|
||||
type: String,
|
||||
default: "42px", // Can be: '24px', '32px', '42px', '56px', etc.
|
||||
},
|
||||
});
|
||||
|
||||
const isHovered = ref(false)
|
||||
const isHovered = ref(false);
|
||||
|
||||
// Load Google Font
|
||||
if (typeof document !== 'undefined') {
|
||||
const link = document.createElement('link')
|
||||
link.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@800;900&display=swap'
|
||||
link.rel = 'stylesheet'
|
||||
document.head.appendChild(link)
|
||||
if (typeof document !== "undefined") {
|
||||
const link = document.createElement("link");
|
||||
link.href =
|
||||
"https://fonts.googleapis.com/css2?family=Inter:wght@800;900&display=swap";
|
||||
link.rel = "stylesheet";
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
const props = withDefaults(defineProps<{ title?: string, description?: string, headline?: string }>(), {
|
||||
title: 'title',
|
||||
description: 'description'
|
||||
})
|
||||
const props = withDefaults(
|
||||
defineProps<{ title?: string; description?: string; headline?: string }>(),
|
||||
{
|
||||
title: "title",
|
||||
description: "description",
|
||||
},
|
||||
);
|
||||
|
||||
const title = computed(() => (props.title || '').slice(0, 60))
|
||||
const description = computed(() => (props.description || '').slice(0, 200))
|
||||
const title = computed(() => (props.title || "").slice(0, 60));
|
||||
const description = computed(() => (props.description || "").slice(0, 200));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { useClipboard } from "@vueuse/core";
|
||||
|
||||
const route = useRoute()
|
||||
const toast = useToast()
|
||||
const { copy, copied } = useClipboard()
|
||||
const site = useSiteConfig()
|
||||
const isCopying = ref(false)
|
||||
console.log(site)
|
||||
const route = useRoute();
|
||||
const toast = useToast();
|
||||
const { copy, copied } = useClipboard();
|
||||
const site = useSiteConfig();
|
||||
const isCopying = ref(false);
|
||||
console.log(site);
|
||||
|
||||
const mdPath = computed(() => `${site.url}/raw${route.path}.md`)
|
||||
const mdPath = computed(() => `${site.url}/raw${route.path}.md`);
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Copy Markdown link',
|
||||
icon: 'i-lucide-link',
|
||||
onSelect() {
|
||||
copy(mdPath.value)
|
||||
toast.add({
|
||||
title: 'Copied to clipboard',
|
||||
icon: 'i-lucide-check-circle'
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'View as Markdown',
|
||||
icon: 'i-simple-icons:markdown',
|
||||
target: '_blank',
|
||||
to: `/raw${route.path}.md`
|
||||
},
|
||||
{
|
||||
label: 'Open in ChatGPT',
|
||||
icon: 'i-simple-icons:openai',
|
||||
target: '_blank',
|
||||
to: `https://chatgpt.com/?hints=search&q=${encodeURIComponent(`Read ${mdPath.value} so I can ask questions about it.`)}`
|
||||
},
|
||||
{
|
||||
label: 'Open in Claude',
|
||||
icon: 'i-simple-icons:anthropic',
|
||||
target: '_blank',
|
||||
to: `https://claude.ai/new?q=${encodeURIComponent(`Read ${mdPath.value} so I can ask questions about it.`)}`
|
||||
}
|
||||
]
|
||||
{
|
||||
label: "Copy Markdown link",
|
||||
icon: "i-lucide-link",
|
||||
onSelect() {
|
||||
copy(mdPath.value);
|
||||
toast.add({
|
||||
title: "Copied to clipboard",
|
||||
icon: "i-lucide-check-circle",
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "View as Markdown",
|
||||
icon: "i-simple-icons:markdown",
|
||||
target: "_blank",
|
||||
to: `/raw${route.path}.md`,
|
||||
},
|
||||
{
|
||||
label: "Open in ChatGPT",
|
||||
icon: "i-simple-icons:openai",
|
||||
target: "_blank",
|
||||
to: `https://chatgpt.com/?hints=search&q=${encodeURIComponent(`Read ${mdPath.value} so I can ask questions about it.`)}`,
|
||||
},
|
||||
{
|
||||
label: "Open in Claude",
|
||||
icon: "i-simple-icons:anthropic",
|
||||
target: "_blank",
|
||||
to: `https://claude.ai/new?q=${encodeURIComponent(`Read ${mdPath.value} so I can ask questions about it.`)}`,
|
||||
},
|
||||
];
|
||||
|
||||
async function copyPage() {
|
||||
isCopying.value = true
|
||||
copy(await $fetch<string>(`/raw${route.path}.md`))
|
||||
isCopying.value = false
|
||||
isCopying.value = true;
|
||||
copy(await $fetch<string>(`/raw${route.path}.md`));
|
||||
isCopying.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
const { isLoading } = useLoadingIndicator()
|
||||
const { isLoading } = useLoadingIndicator();
|
||||
|
||||
const appear = ref(false)
|
||||
const appeared = ref(false)
|
||||
const appear = ref(false);
|
||||
const appeared = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
appear.value = true
|
||||
setTimeout(() => {
|
||||
appeared.value = true
|
||||
}, 1000)
|
||||
}, 0)
|
||||
})
|
||||
setTimeout(() => {
|
||||
appear.value = true;
|
||||
setTimeout(() => {
|
||||
appeared.value = true;
|
||||
}, 1000);
|
||||
}, 0);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,58 +1,67 @@
|
||||
<script setup lang="ts">
|
||||
interface Star {
|
||||
x: number
|
||||
y: number
|
||||
size: number
|
||||
x: number;
|
||||
y: number;
|
||||
size: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
starCount?: number
|
||||
color?: string
|
||||
speed?: 'slow' | 'normal' | 'fast'
|
||||
size?: { min: number, max: number }
|
||||
}>(), {
|
||||
starCount: 300,
|
||||
color: 'var(--ui-primary)',
|
||||
speed: 'normal',
|
||||
size: () => ({
|
||||
min: 1,
|
||||
max: 2
|
||||
})
|
||||
})
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
starCount?: number;
|
||||
color?: string;
|
||||
speed?: "slow" | "normal" | "fast";
|
||||
size?: { min: number; max: number };
|
||||
}>(),
|
||||
{
|
||||
starCount: 300,
|
||||
color: "var(--ui-primary)",
|
||||
speed: "normal",
|
||||
size: () => ({
|
||||
min: 1,
|
||||
max: 2,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
// Generate random star positions and sizes
|
||||
const generateStars = (count: number): Star[] => {
|
||||
return Array.from({ length: count }, () => ({
|
||||
x: Math.floor(Math.random() * 2000),
|
||||
y: Math.floor(Math.random() * 2000),
|
||||
size: typeof props.size === 'number'
|
||||
? props.size
|
||||
: Math.random() * (props.size.max - props.size.min) + props.size.min
|
||||
}))
|
||||
}
|
||||
return Array.from({ length: count }, () => ({
|
||||
x: Math.floor(Math.random() * 2000),
|
||||
y: Math.floor(Math.random() * 2000),
|
||||
size:
|
||||
typeof props.size === "number"
|
||||
? props.size
|
||||
: Math.random() * (props.size.max - props.size.min) + props.size.min,
|
||||
}));
|
||||
};
|
||||
|
||||
// Define speed configurations once
|
||||
const speedMap = {
|
||||
slow: { duration: 200, opacity: 0.5, ratio: 0.3 },
|
||||
normal: { duration: 150, opacity: 0.75, ratio: 0.3 },
|
||||
fast: { duration: 100, opacity: 1, ratio: 0.4 }
|
||||
}
|
||||
slow: { duration: 200, opacity: 0.5, ratio: 0.3 },
|
||||
normal: { duration: 150, opacity: 0.75, ratio: 0.3 },
|
||||
fast: { duration: 100, opacity: 1, ratio: 0.4 },
|
||||
};
|
||||
|
||||
// Use a more efficient approach to generate and store stars
|
||||
const stars = useState<{ slow: Star[], normal: Star[], fast: Star[] }>('stars', () => {
|
||||
return {
|
||||
slow: generateStars(Math.floor(props.starCount * speedMap.slow.ratio)),
|
||||
normal: generateStars(Math.floor(props.starCount * speedMap.normal.ratio)),
|
||||
fast: generateStars(Math.floor(props.starCount * speedMap.fast.ratio))
|
||||
}
|
||||
})
|
||||
const stars = useState<{ slow: Star[]; normal: Star[]; fast: Star[] }>(
|
||||
"stars",
|
||||
() => {
|
||||
return {
|
||||
slow: generateStars(Math.floor(props.starCount * speedMap.slow.ratio)),
|
||||
normal: generateStars(
|
||||
Math.floor(props.starCount * speedMap.normal.ratio),
|
||||
),
|
||||
fast: generateStars(Math.floor(props.starCount * speedMap.fast.ratio)),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// Compute star layers with different speeds and opacities
|
||||
const starLayers = computed(() => [
|
||||
{ stars: stars.value.fast, ...speedMap.fast },
|
||||
{ stars: stars.value.normal, ...speedMap.normal },
|
||||
{ stars: stars.value.slow, ...speedMap.slow }
|
||||
])
|
||||
{ stars: stars.value.fast, ...speedMap.fast },
|
||||
{ stars: stars.value.normal, ...speedMap.normal },
|
||||
{ stars: stars.value.slow, ...speedMap.slow },
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import type { NuxtError } from '#app'
|
||||
import type { NuxtError } from "#app";
|
||||
|
||||
defineProps<{
|
||||
error: NuxtError
|
||||
}>()
|
||||
error: NuxtError;
|
||||
}>();
|
||||
|
||||
useHead({
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
}
|
||||
})
|
||||
htmlAttrs: {
|
||||
lang: "en",
|
||||
},
|
||||
});
|
||||
|
||||
useSeoMeta({
|
||||
title: 'Page not found',
|
||||
description: 'We are sorry but this page could not be found.'
|
||||
})
|
||||
title: "Page not found",
|
||||
description: "We are sorry but this page could not be found.",
|
||||
});
|
||||
|
||||
const { data: navigation } = await useAsyncData('navigation', () => queryCollectionNavigation('docs'))
|
||||
const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSections('docs'), {
|
||||
server: false
|
||||
})
|
||||
const { data: navigation } = await useAsyncData("navigation", () =>
|
||||
queryCollectionNavigation("docs"),
|
||||
);
|
||||
const { data: files } = useLazyAsyncData(
|
||||
"search",
|
||||
() => queryCollectionSearchSections("docs"),
|
||||
{
|
||||
server: false,
|
||||
},
|
||||
);
|
||||
|
||||
provide('navigation', navigation)
|
||||
provide("navigation", navigation);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { ContentNavigationItem } from '@nuxt/content'
|
||||
import type { ContentNavigationItem } from "@nuxt/content";
|
||||
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>("navigation");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,55 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import type { ContentNavigationItem } from '@nuxt/content'
|
||||
import { findPageHeadline } from '@nuxt/content/utils'
|
||||
import type { ContentNavigationItem } from "@nuxt/content";
|
||||
import { findPageHeadline } from "@nuxt/content/utils";
|
||||
|
||||
definePageMeta({
|
||||
layout: 'docs'
|
||||
})
|
||||
layout: "docs",
|
||||
});
|
||||
|
||||
const route = useRoute()
|
||||
const { toc } = useAppConfig()
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
const route = useRoute();
|
||||
const { toc } = useAppConfig();
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>("navigation");
|
||||
|
||||
const { data: page } = await useAsyncData(route.path, () => queryCollection('docs').path(route.path).first())
|
||||
const { data: page } = await useAsyncData(route.path, () =>
|
||||
queryCollection("docs").path(route.path).first(),
|
||||
);
|
||||
if (!page.value) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Page not found",
|
||||
fatal: true,
|
||||
});
|
||||
}
|
||||
|
||||
const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
|
||||
return queryCollectionItemSurroundings('docs', route.path, {
|
||||
fields: ['description']
|
||||
})
|
||||
})
|
||||
return queryCollectionItemSurroundings("docs", route.path, {
|
||||
fields: ["description"],
|
||||
});
|
||||
});
|
||||
|
||||
const title = page.value.seo?.title || page.value.title
|
||||
const description = page.value.seo?.description || page.value.description
|
||||
const title = page.value.seo?.title || page.value.title;
|
||||
const description = page.value.seo?.description || page.value.description;
|
||||
|
||||
useSeoMeta({
|
||||
title,
|
||||
ogTitle: title,
|
||||
description,
|
||||
ogDescription: description
|
||||
})
|
||||
title,
|
||||
ogTitle: title,
|
||||
description,
|
||||
ogDescription: description,
|
||||
});
|
||||
|
||||
const headline = computed(() => findPageHeadline(navigation?.value, page.value?.path))
|
||||
const headline = computed(() =>
|
||||
findPageHeadline(navigation?.value, page.value?.path),
|
||||
);
|
||||
|
||||
defineOgImageComponent('Docs', {
|
||||
headline: headline.value
|
||||
})
|
||||
defineOgImageComponent("Docs", {
|
||||
headline: headline.value,
|
||||
});
|
||||
|
||||
const links = computed(() => {
|
||||
const links = []
|
||||
if (toc?.bottom?.edit) {
|
||||
links.push({
|
||||
icon: 'i-lucide-external-link',
|
||||
label: 'Edit this page',
|
||||
to: `${toc.bottom.edit}/${page?.value?.stem}.${page?.value?.extension}`,
|
||||
target: '_blank'
|
||||
})
|
||||
}
|
||||
const links = [];
|
||||
if (toc?.bottom?.edit) {
|
||||
links.push({
|
||||
icon: "i-lucide-external-link",
|
||||
label: "Edit this page",
|
||||
to: `${toc.bottom.edit}/${page?.value?.stem}.${page?.value?.extension}`,
|
||||
target: "_blank",
|
||||
});
|
||||
}
|
||||
|
||||
return [...links, ...(toc?.bottom?.links || [])].filter(Boolean)
|
||||
})
|
||||
return [...links, ...(toc?.bottom?.links || [])].filter(Boolean);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
import { defineContentConfig, defineCollection, z } from '@nuxt/content'
|
||||
import { defineContentConfig, defineCollection, z } from "@nuxt/content";
|
||||
|
||||
export default defineContentConfig({
|
||||
collections: {
|
||||
landing: defineCollection({
|
||||
type: 'page',
|
||||
source: 'index.md'
|
||||
}),
|
||||
docs: defineCollection({
|
||||
type: 'page',
|
||||
source: {
|
||||
include: '**',
|
||||
},
|
||||
schema: z.object({
|
||||
links: z.array(z.object({
|
||||
label: z.string(),
|
||||
icon: z.string(),
|
||||
to: z.string(),
|
||||
target: z.string().optional()
|
||||
})).optional()
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
collections: {
|
||||
landing: defineCollection({
|
||||
type: "page",
|
||||
source: "index.md",
|
||||
}),
|
||||
docs: defineCollection({
|
||||
type: "page",
|
||||
source: {
|
||||
include: "**",
|
||||
},
|
||||
schema: z.object({
|
||||
links: z
|
||||
.array(
|
||||
z.object({
|
||||
label: z.string(),
|
||||
icon: z.string(),
|
||||
to: z.string(),
|
||||
target: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
}),
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @ts-check
|
||||
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||
import withNuxt from "./.nuxt/eslint.config.mjs";
|
||||
|
||||
export default withNuxt(
|
||||
// Your custom configs here
|
||||
)
|
||||
// Your custom configs here
|
||||
);
|
||||
|
||||
@@ -1,103 +1,102 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
app: {
|
||||
baseURL: '/kompose/',
|
||||
},
|
||||
modules: [
|
||||
'@nuxt/eslint',
|
||||
'@nuxt/image',
|
||||
'@nuxt/ui',
|
||||
'@nuxt/content',
|
||||
'nuxt-og-image',
|
||||
'nuxt-llms'
|
||||
],
|
||||
app: {
|
||||
baseURL: "/kompose/",
|
||||
},
|
||||
modules: [
|
||||
"@nuxt/eslint",
|
||||
"@nuxt/image",
|
||||
"@nuxt/ui",
|
||||
"@nuxt/content",
|
||||
"nuxt-og-image",
|
||||
"nuxt-llms",
|
||||
],
|
||||
|
||||
// content: {
|
||||
// build: {
|
||||
// markdown: {
|
||||
// // Object syntax can be used to override default options
|
||||
// remarkPlugins: {
|
||||
// // Override remark-emoji options
|
||||
// 'remark-emoji': {
|
||||
// options: {
|
||||
// emoticon: true
|
||||
// }
|
||||
// },
|
||||
// // Disable remark-gfm
|
||||
// 'remark-gfm': false,
|
||||
// // Add remark-oembed
|
||||
// 'remark-oembed': {
|
||||
// // Options
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// content: {
|
||||
// build: {
|
||||
// markdown: {
|
||||
// // Object syntax can be used to override default options
|
||||
// remarkPlugins: {
|
||||
// // Override remark-emoji options
|
||||
// 'remark-emoji': {
|
||||
// options: {
|
||||
// emoticon: true
|
||||
// }
|
||||
// },
|
||||
// // Disable remark-gfm
|
||||
// 'remark-gfm': false,
|
||||
// // Add remark-oembed
|
||||
// 'remark-oembed': {
|
||||
// // Options
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
|
||||
devtools: {
|
||||
enabled: false
|
||||
},
|
||||
devtools: {
|
||||
enabled: false,
|
||||
},
|
||||
|
||||
css: ['~/assets/css/main.css'],
|
||||
css: ["~/assets/css/main.css"],
|
||||
|
||||
content: {
|
||||
build: {
|
||||
markdown: {
|
||||
toc: {
|
||||
searchDepth: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
content: {
|
||||
build: {
|
||||
markdown: {
|
||||
toc: {
|
||||
searchDepth: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
compatibilityDate: '2024-07-11',
|
||||
compatibilityDate: "2024-07-11",
|
||||
|
||||
nitro: {
|
||||
prerender: {
|
||||
routes: [
|
||||
'/'
|
||||
],
|
||||
crawlLinks: true,
|
||||
autoSubfolderIndex: false
|
||||
}
|
||||
},
|
||||
nitro: {
|
||||
prerender: {
|
||||
routes: ["/"],
|
||||
crawlLinks: true,
|
||||
autoSubfolderIndex: false,
|
||||
},
|
||||
},
|
||||
|
||||
eslint: {
|
||||
config: {
|
||||
stylistic: {
|
||||
commaDangle: 'never',
|
||||
braceStyle: '1tbs'
|
||||
}
|
||||
}
|
||||
},
|
||||
eslint: {
|
||||
config: {
|
||||
stylistic: {
|
||||
commaDangle: "never",
|
||||
braceStyle: "1tbs",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
icon: {
|
||||
provider: 'iconify'
|
||||
},
|
||||
icon: {
|
||||
provider: "iconify",
|
||||
},
|
||||
|
||||
llms: {
|
||||
domain: 'https://docs-template.nuxt.dev/',
|
||||
title: 'Nuxt Docs Template',
|
||||
description: 'A template for building documentation with Nuxt UI and Nuxt Content.',
|
||||
full: {
|
||||
title: 'Nuxt Docs Template - Full Documentation',
|
||||
description: 'This is the full documentation for the Nuxt Docs Template.'
|
||||
},
|
||||
sections: [
|
||||
{
|
||||
title: 'Getting Started',
|
||||
contentCollection: 'docs',
|
||||
contentFilters: [
|
||||
{ field: 'path', operator: 'LIKE', value: '/getting-started%' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Essentials',
|
||||
contentCollection: 'docs',
|
||||
contentFilters: [
|
||||
{ field: 'path', operator: 'LIKE', value: '/essentials%' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
llms: {
|
||||
domain: "https://docs-template.nuxt.dev/",
|
||||
title: "Nuxt Docs Template",
|
||||
description:
|
||||
"A template for building documentation with Nuxt UI and Nuxt Content.",
|
||||
full: {
|
||||
title: "Nuxt Docs Template - Full Documentation",
|
||||
description: "This is the full documentation for the Nuxt Docs Template.",
|
||||
},
|
||||
sections: [
|
||||
{
|
||||
title: "Getting Started",
|
||||
contentCollection: "docs",
|
||||
contentFilters: [
|
||||
{ field: "path", operator: "LIKE", value: "/getting-started%" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Essentials",
|
||||
contentCollection: "docs",
|
||||
contentFilters: [
|
||||
{ field: "path", operator: "LIKE", value: "/essentials%" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
{
|
||||
"name": "nuxt-ui-template-docs",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"generate": "nuxi generate",
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare",
|
||||
"lint": "eslint .",
|
||||
"typecheck": "nuxt typecheck"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify-json/lucide": "^1.2.68",
|
||||
"@iconify-json/simple-icons": "^1.2.54",
|
||||
"@iconify-json/vscode-icons": "^1.2.30",
|
||||
"@nuxt/content": "^3.7.1",
|
||||
"@nuxt/image": "^1.11.0",
|
||||
"@nuxt/ui": "^4.0.1",
|
||||
"@nuxtjs/mdc": "^0.17.4",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@vite-pwa/nuxt": "^1.0.4",
|
||||
"better-sqlite3": "^12.4.1",
|
||||
"nuxt": "^4.1.2",
|
||||
"nuxt-llms": "0.1.3",
|
||||
"nuxt-og-image": "^5.1.11",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint": "^1.9.0",
|
||||
"eslint": "^9.37.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vue-tsc": "^3.1.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"unimport": "4.1.1"
|
||||
}
|
||||
"name": "nuxt-ui-template-docs",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"generate": "nuxi generate",
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare",
|
||||
"lint": "eslint .",
|
||||
"typecheck": "nuxt typecheck"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify-json/lucide": "^1.2.68",
|
||||
"@iconify-json/simple-icons": "^1.2.54",
|
||||
"@iconify-json/vscode-icons": "^1.2.30",
|
||||
"@nuxt/content": "^3.7.1",
|
||||
"@nuxt/image": "^1.11.0",
|
||||
"@nuxt/ui": "^4.0.1",
|
||||
"@nuxtjs/mdc": "^0.17.4",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@vite-pwa/nuxt": "^1.0.4",
|
||||
"better-sqlite3": "^12.4.1",
|
||||
"nuxt": "^4.1.2",
|
||||
"nuxt-llms": "0.1.3",
|
||||
"nuxt-og-image": "^5.1.11",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint": "^1.9.0",
|
||||
"eslint": "^9.37.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vue-tsc": "^3.1.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"unimport": "4.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"extends": [
|
||||
"github>nuxt/renovate-config-nuxt"
|
||||
],
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true
|
||||
},
|
||||
"packageRules": [{
|
||||
"matchDepTypes": ["resolutions"],
|
||||
"enabled": false
|
||||
}],
|
||||
"postUpdateOptions": ["pnpmDedupe"]
|
||||
"extends": ["github>nuxt/renovate-config-nuxt"],
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true
|
||||
},
|
||||
"packageRules": [
|
||||
{
|
||||
"matchDepTypes": ["resolutions"],
|
||||
"enabled": false
|
||||
}
|
||||
],
|
||||
"postUpdateOptions": ["pnpmDedupe"]
|
||||
}
|
||||
|
||||
@@ -1,27 +1,40 @@
|
||||
import { withLeadingSlash } from 'ufo'
|
||||
import { stringify } from 'minimark/stringify'
|
||||
import { queryCollection } from '@nuxt/content/nitro'
|
||||
import type { Collections } from '@nuxt/content'
|
||||
import { withLeadingSlash } from "ufo";
|
||||
import { stringify } from "minimark/stringify";
|
||||
import { queryCollection } from "@nuxt/content/nitro";
|
||||
import type { Collections } from "@nuxt/content";
|
||||
|
||||
export default eventHandler(async (event) => {
|
||||
const slug = getRouterParams(event)['slug.md']
|
||||
if (!slug?.endsWith('.md')) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
|
||||
}
|
||||
const slug = getRouterParams(event)["slug.md"];
|
||||
if (!slug?.endsWith(".md")) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Page not found",
|
||||
fatal: true,
|
||||
});
|
||||
}
|
||||
|
||||
const path = withLeadingSlash(slug.replace('.md', ''))
|
||||
const path = withLeadingSlash(slug.replace(".md", ""));
|
||||
|
||||
const page = await queryCollection(event, 'docs' as keyof Collections).path(path).first()
|
||||
if (!page) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
|
||||
}
|
||||
const page = await queryCollection(event, "docs" as keyof Collections)
|
||||
.path(path)
|
||||
.first();
|
||||
if (!page) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Page not found",
|
||||
fatal: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Add title and description to the top of the page if missing
|
||||
if (page.body.value[0]?.[0] !== 'h1') {
|
||||
page.body.value.unshift(['blockquote', {}, page.description])
|
||||
page.body.value.unshift(['h1', {}, page.title])
|
||||
}
|
||||
// Add title and description to the top of the page if missing
|
||||
if (page.body.value[0]?.[0] !== "h1") {
|
||||
page.body.value.unshift(["blockquote", {}, page.description]);
|
||||
page.body.value.unshift(["h1", {}, page.title]);
|
||||
}
|
||||
|
||||
setHeader(event, 'Content-Type', 'text/markdown; charset=utf-8')
|
||||
return stringify({ ...page.body, type: 'minimark' }, { format: 'markdown/html' })
|
||||
})
|
||||
setHeader(event, "Content-Type", "text/markdown; charset=utf-8");
|
||||
return stringify(
|
||||
{ ...page.body, type: "minimark" },
|
||||
{ format: "markdown/html" },
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user