lint:fix all

This commit is contained in:
2025-07-29 00:32:57 +08:00
parent 7d2f57df97
commit 1745a54eb6
34 changed files with 820 additions and 606 deletions

View File

@@ -1,66 +1,93 @@
<script setup lang="ts">
// import type { NavigationMenuItem } from '@nuxt/ui'
import type { ContentNavigationItem } from "@nuxt/content";
const navigation = inject<Ref<ContentNavigationItem[]>>("navigation");
import type { ContentNavigationItem } from '@nuxt/content'
const isSettingsOpen = ref(false);
const isLoginModalOpen = ref(false);
const isRegisterModalOpen = ref(false);
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
const isSettingsOpen = ref(false)
const isLoginModalOpen = ref(false)
const isRegisterModalOpen = ref(false)
// const { header } = useAppConfig();
// 定义 props 来接收侧边栏状态和切换函数
interface Props {
isSidebarOpen?: boolean;
toggleSidebar?: () => void;
isSidebarOpen?: boolean
toggleSidebar?: () => void
}
const Props = withDefaults(defineProps<Props>(), {
isSidebarOpen: false,
toggleSidebar: () => { },
});
toggleSidebar: () => { }
})
// 登录注册函数
const handleLoginRegister = (type: "login" | "register") => {
if (type === "login") {
isLoginModalOpen.value = true;
} else if (type === "register") {
isRegisterModalOpen.value = true;
const handleLoginRegister = (type: 'login' | 'register') => {
if (type === 'login') {
isLoginModalOpen.value = true
} else if (type === 'register') {
isRegisterModalOpen.value = true
}
};
}
</script>
<template>
<UHeader toggle-side="left" title="Estel Docs" mode="modal" class="bg-gray-50 dark:bg-gray-900">
<UHeader
toggle-side="left"
title="Estel Docs"
mode="modal"
class="bg-gray-50 dark:bg-gray-900"
>
<template #title>
<h6></h6>
<h6 />
</template>
<template #body>
<LogoPro class="h-5 w-auto mb-4" />
<DocsAsideLeftTop />
<div class="mt-4 mb-4 border-t border-gray-200 dark:border-gray-700 w-9/10 mx-5" />
<UContentNavigation highlight :navigation="navigation" color="primary" type="single" variant="pill" />
<UContentNavigation
highlight
:navigation="navigation"
color="primary"
type="single"
variant="pill"
/>
</template>
<template #right>
<UContentSearchButton class="lg:hidden" />
<UColorModeButton />
<button
class=" p-2 rounded-md text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
title="页面设置" @click="isSettingsOpen = !isSettingsOpen">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
</button>
class=" p-2 rounded-md text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
title="页面设置"
@click="isSettingsOpen = !isSettingsOpen"
>
<svg
class="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
</button>
<UTooltip text="Open on GitHub" :kbds="['meta', 'G']">
<UTooltip
text="Open on GitHub"
:kbds="['meta', 'G']"
>
<UButton
color="neutral"
variant="ghost"
@@ -71,32 +98,45 @@ const handleLoginRegister = (type: "login" | "register") => {
/>
</UTooltip>
<div class="flex items-center space-x-2">
<button @click="handleLoginRegister('login')"
class="px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors">
登录
</button>
<button @click="handleLoginRegister('register')"
class="text-sm font-medium text-white bg-primary rounded-md px-3 py-2 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary transition-colors">
注册
</button>
</div>
<button
class="px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors"
@click="handleLoginRegister('login')"
>
登录
</button>
<button
class="text-sm font-medium text-white bg-primary rounded-md px-3 py-2 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary transition-colors"
@click="handleLoginRegister('register')"
>
注册
</button>
</div>
</template>
</UHeader>
<!-- Theme Settings Panel -->
<ThemeSettings :is-open="isSettingsOpen" @close="isSettingsOpen = false" />
<ThemeSettings
:is-open="isSettingsOpen"
@close="isSettingsOpen = false"
/>
<!-- 登录模态框 -->
<UModal v-model:open="isLoginModalOpen" title="登录" :dismissible="false">
<UModal
v-model:open="isLoginModalOpen"
title="登录"
:dismissible="false"
>
<template #body>
<authLogin />
</template>
</UModal>
<!-- 注册模态框 -->
<UModal v-model:open="isRegisterModalOpen" title="注册" :dismissible="false">
<UModal
v-model:open="isRegisterModalOpen"
title="注册"
:dismissible="false"
>
<template #body>
<authRegister />
</template>

View File

@@ -1,9 +1,10 @@
<template>
<UPage>
<div
class="w-64 bg-white dark:bg-gray-900
flex flex-col h-screen border-r border-gray-200 dark:border-gray-700
overflow-hidden">
class="w-64 bg-white dark:bg-gray-900
flex flex-col h-screen border-r border-gray-200 dark:border-gray-700
overflow-hidden"
>
<div class="flex-shrink-0 p-4 border-gray-200 dark:border-gray-700">
<!-- Logo -->
<LogoPro />
@@ -12,29 +13,38 @@
<!-- Search Box -->
<div class="p-4 border-gray-200 dark:border-gray-700">
<ClientOnly>
<UContentSearchButton :collapsed="false" label="搜索文档" class="w-full"
color="primary" />
<UContentSearchButton
:collapsed="false"
label="搜索文档"
class="w-full"
color="primary"
/>
</ClientOnly>
</div>
<!-- 可滚动的导航区域 -->
<div class=" h-full overflow-y-auto ">
<!-- 导航 Section -->
<div>
<NuxtLink to="/"
<NuxtLink
to="/"
class="flex items-center px-4 py-2 text-sm font-medium rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 hover:shadow-sm transition-all duration-200"
:class="{
' text-blue-600 dark:text-blue-400 ':
$route.path === '/',
}">
<Icon name="lucide-home" class="text-primary mr-2" size="20" />
$route.path === '/'
}"
>
<Icon
name="lucide-home"
class="text-primary mr-2"
size="20"
/>
站点首页
</NuxtLink>
<div class="px-2">
<DocsAsideLeftTop />
</div>
</div>
</div>
<!-- 分隔线 -->
@@ -42,7 +52,13 @@
<!-- 文档目录导航 -->
<div class="mt-6 flex items-center justify-start pl-4 w-full">
<UContentNavigation highlight :navigation="navigation" color="primary" type="single" variant="pill" />
<UContentNavigation
highlight
:navigation="navigation"
color="primary"
type="single"
variant="pill"
/>
</div>
</div>
</div>
@@ -50,6 +66,7 @@
</template>
<script setup lang="ts">
import type { ContentNavigationItem } from "@nuxt/content";
const navigation = inject<Ref<ContentNavigationItem[]>>("navigation");
import type { ContentNavigationItem } from '@nuxt/content'
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
</script>

View File

@@ -1,8 +1,8 @@
<template>
<div>
<UContentNavigation
:navigation="directoryNavigation"
highlight
<div>
<UContentNavigation
:navigation="directoryNavigation"
highlight
color="primary"
variant="pill"
/>
@@ -18,8 +18,8 @@ const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
// 处理导航数据,只显示一级目录和根目录文件
const directoryNavigation = computed(() => {
if (!navigation?.value) return []
return navigation.value.map(item => {
return navigation.value.map((item) => {
// 如果是根目录文件(没有 children直接返回
if (!item.children || item.children.length === 0) {
return {
@@ -29,7 +29,7 @@ const directoryNavigation = computed(() => {
active: Boolean(item.active)
}
}
// 如果是一级目录,只保留目录本身,不显示子项
return {
title: item.title,
@@ -45,4 +45,4 @@ const directoryNavigation = computed(() => {
// 调试信息
// console.log('ContentDirectory: Navigation data:', navigation.value)
// console.log('ContentDirectory: Processed navigation:', directoryNavigation.value)
</script>
</script>

View File

@@ -1,7 +1,7 @@
<template>
<div class="w-full bg-gray-50 dark:bg-gray-900 min-h-screen mt-4">
<!-- 响应式卡片网格 -->
<!--
<div class="w-full bg-gray-50 dark:bg-gray-900 min-h-screen mt-4">
<!-- 响应式卡片网格 -->
<!--
这个div使用了Tailwind CSS的类来实现响应式的卡片网格布局
- grid将容器设置为网格布局
- grid-cols-1在小屏幕下每行显示1列
@@ -11,88 +11,103 @@
- max-w-8xl设置最大宽度为8xl防止内容过宽
- mx-auto左右自动外边距使网格居中显示
-->
<div class="grid grid-cols-1 xs:grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4 gap-4 w-full mx-auto">
<div v-for="item in firstLevelItems" :key="item.path"
class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-5 sm:p-6 shadow-sm hover:shadow-md transition-all duration-200 cursor-pointer"
@click="navigateTo(item.path)">
<!-- 卡片头部 -->
<div class="flex items-center justify-between mb-1">
<h2 class="font-sans text-xl sm:text-xl lg:text-2xl font-bold text-gray-900 dark:text-white leading-tight">
{{ item.title }}
</h2>
<span class="text-sm sm:text-base lg:text-lg text-gray-600 dark:text-gray-400 font-normal">
<span class="text-primary mr-0.3">{{ getChildrenCount(item) }}</span>
</span>
</div>
<!-- 子页面列表 -->
<div v-if="getChildrenTitles(item).length > 0" class="">
<div v-for="(child, index) in getChildrenWithIcons(item).slice(0, 5)" :key="index"
class="flex items-center justify-between
text-sm sm:text-base lg:text-lg text-gray-700 dark:text-gray-300
hover:text-blue-600 dark:hover:text-blue-400
transition-colors duration-200 py-1
border-b border-gray-200 dark:border-gray-700 pt-2">
<div class="flex items-center flex-1 min-w-0 pl-1 ">
<UIcon :name="(typeof child.icon === 'string' ? child.icon : 'lucide-file-text')" class="mr-2 text-gray-400" size="14" />
<span class="text-base font-medium font-sans">{{ child.title }}</span>
</div>
<UIcon name="lucide-chevron-right" class="text-gray-400 flex-shrink-0 ml-2" size="16" />
</div>
</div>
</div>
<div class="grid grid-cols-1 xs:grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4 gap-4 w-full mx-auto">
<div
v-for="item in firstLevelItems"
:key="item.path"
class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-5 sm:p-6 shadow-sm hover:shadow-md transition-all duration-200 cursor-pointer"
@click="navigateTo(item.path)"
>
<!-- 卡片头部 -->
<div class="flex items-center justify-between mb-1">
<h2 class="font-sans text-xl sm:text-xl lg:text-2xl font-bold text-gray-900 dark:text-white leading-tight">
{{ item.title }}
</h2>
<span class="text-sm sm:text-base lg:text-lg text-gray-600 dark:text-gray-400 font-normal">
<span class="text-primary mr-0.3">{{ getChildrenCount(item) }}</span>
</span>
</div>
<!-- 子页面列表 -->
<div
v-if="getChildrenTitles(item).length > 0"
class=""
>
<div
v-for="(child, index) in getChildrenWithIcons(item).slice(0, 5)"
:key="index"
class="flex items-center justify-between
text-sm sm:text-base lg:text-lg text-gray-700 dark:text-gray-300
hover:text-blue-600 dark:hover:text-blue-400
transition-colors duration-200 py-1
border-b border-gray-200 dark:border-gray-700 pt-2"
>
<div class="flex items-center flex-1 min-w-0 pl-1 ">
<UIcon
:name="(typeof child.icon === 'string' ? child.icon : 'lucide-file-text')"
class="mr-2 text-gray-400"
size="14"
/>
<span class="text-base font-medium font-sans">{{ child.title }}</span>
</div>
<UIcon
name="lucide-chevron-right"
class="text-gray-400 flex-shrink-0 ml-2"
size="16"
/>
</div>
</div>
</div>
</div>
</div>
</template>
<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 firstLevelItems = computed(() => {
if (!navigation?.value) return [];
return navigation.value
.filter(item => item.title && item.path)
.map(item => ({
...item,
description: item.description,
icon: item.icon || 'lucide-book-open'
}));
});
if (!navigation?.value) return []
return navigation.value
.filter(item => item.title && item.path)
.map(item => ({
...item,
description: item.description,
icon: item.icon || 'lucide-book-open'
}))
})
// 获取子页面数量
const getChildrenCount = (item: ContentNavigationItem) => {
return item.children?.length || 0;
};
return item.children?.length || 0
}
// 获取子页面标题列表
const getChildrenTitles = (item: ContentNavigationItem) => {
if (!item.children) return [];
return item.children.map(child => child.title).filter(Boolean);
};
if (!item.children) return []
return item.children.map(child => child.title).filter(Boolean)
}
// 获取子页面数据(包含图标)
const getChildrenWithIcons = (item: ContentNavigationItem) => {
if (!item.children) return [];
return item.children.filter(child => child.title);
};
if (!item.children) return []
return item.children.filter(child => child.title)
}
// 获取描述信息
const getDescription = (item: ContentNavigationItem) => {
if (item.children && item.children.length > 0) {
return `${item.children.length} 个子页面`;
}
return "文档页面";
};
if (item.children && item.children.length > 0) {
return `${item.children.length} 个子页面`
}
return '文档页面'
}
// 导航方法
const navigateTo = (path: string) => {
if (path) {
window.location.href = path;
}
};
</script>
if (path) {
window.location.href = path
}
}
</script>

View File

@@ -3,20 +3,20 @@
</script>
<template>
<div class="w-full top-0 left-0 bg-gray-50 dark:bg-gray-900">
<!-- 欢迎卡片 -->
<div
class="bg-slate-200 dark:bg-slate-600 rounded-lg border border-gray-200 dark:border-gray-700 p-2 sm:p-4 shadow-sm">
<h1 class="text-xl font-bold text-gray-900 dark:text-white mb-2">
Hi 👋, 欢迎使用简单文档系统
</h1>
<!-- 编号列表 -->
<div class="mt-2 text-base text-gray-700 dark:text-gray-300">
1. 登录网站<br>
2. 创建文档为文档添加文章<br>
3. 拖拽文章标题进行排序分享文档
</div>
</div>
<div class="w-full top-0 left-0 bg-gray-50 dark:bg-gray-900">
<!-- 欢迎卡片 -->
<div
class="bg-slate-200 dark:bg-slate-600 rounded-lg border border-gray-200 dark:border-gray-700 p-2 sm:p-4 shadow-sm"
>
<h1 class="text-xl font-bold text-gray-900 dark:text-white mb-2">
Hi 👋, 欢迎使用简单文档系统
</h1>
<!-- 编号列表 -->
<div class="mt-2 text-base text-gray-700 dark:text-gray-300">
1. 登录网站<br>
2. 创建文档为文档添加文章<br>
3. 拖拽文章标题进行排序分享文档
</div>
</div>
</div>
</template>

View File

@@ -1,6 +1,9 @@
<template>
<div class="h-8">
<NuxtLink to="/" class="flex items-center space-x-3">
<NuxtLink
to="/"
class="flex items-center space-x-3"
>
<div class="w-8 h-8 bg-primary rounded-xl flex items-center justify-center shadow-md">
<span class="text-white font-bold text-lg">E</span>
</div>

View File

@@ -8,14 +8,16 @@
leave-from-class="translate-x-0"
leave-to-class="translate-x-full"
>
<div
<div
v-if="isOpen"
class="fixed right-0 top-16 h-[calc(100vh-4rem)] w-full sm:w-96 bg-white dark:bg-gray-900 shadow-2xl z-40 overflow-y-auto border-l border-gray-200 dark:border-gray-700 custom-scrollbar"
>
<!-- 头部 -->
<div class="sticky top-0 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700 px-6 py-4">
<div class="flex items-center justify-between">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">页面设置</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
页面设置
</h2>
<UButton
color="neutral"
variant="ghost"
@@ -30,7 +32,9 @@
<div class="p-6 space-y-8">
<!-- 主题 -->
<div>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">主题</h3>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">
主题
</h3>
<div class="grid grid-cols-3 gap-3">
<UButton
v-for="theme in themes"
@@ -47,7 +51,9 @@
<!-- 字体 -->
<div>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">字体</h3>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">
字体
</h3>
<div class="grid grid-cols-3 gap-3">
<UButton
v-for="font in fonts"
@@ -64,7 +70,9 @@
<!-- 字号 -->
<div>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">字号</h3>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">
字号
</h3>
<div class="grid grid-cols-5 gap-2">
<UButton
v-for="size in fontSizes"
@@ -81,7 +89,9 @@
<!-- 主题色 -->
<div>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">主题色</h3>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">
主题色
</h3>
<div class="grid grid-cols-2 gap-3">
<UButton
v-for="color in themeColors"
@@ -93,7 +103,7 @@
@click="selectedThemeColor = color.value"
>
<template #leading>
<div
<div
class="w-4 h-4 rounded-full border border-gray-300 dark:border-gray-600"
:style="{ backgroundColor: color.color }"
/>
@@ -105,7 +115,9 @@
<!-- 自定义主题色 -->
<div>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">自定义主题色</h3>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">
自定义主题色
</h3>
<div class="flex items-center space-x-3">
<input
v-model="customColor"
@@ -124,7 +136,9 @@
<!-- 代码块主题 -->
<div>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">代码块主题</h3>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">
代码块主题
</h3>
<USelect
v-model="selectedCodeTheme"
:options="codeThemes"
@@ -136,7 +150,9 @@
<!-- 图注格式 -->
<div>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">图注格式</h3>
<h3 class="text-base font-medium text-gray-900 dark:text-white mb-4">
图注格式
</h3>
<div class="grid grid-cols-2 gap-3">
<UButton
v-for="format in captionFormats"
@@ -204,7 +220,7 @@ const {
selectedCaptionFormat,
applyCustomColor,
resetSettings
} = useTheme();
} = useTheme()
// 监听键盘事件(只监听 ESC 键)
onMounted(() => {
@@ -213,11 +229,11 @@ onMounted(() => {
emit('close')
}
}
document.addEventListener('keydown', handleKeydown)
onUnmounted(() => {
document.removeEventListener('keydown', handleKeydown)
})
})
</script>
</script>

View File

@@ -29,7 +29,7 @@ const fields = ref([
<template>
<UAuthForm
class="max-w-md"
title="登录"
description="使用社交账号或邮箱登录"

View File

@@ -1,25 +1,34 @@
<template>
<div class="flex flex-row items-center mt-2 mb-2">
<NuxtLink :to="to || href" :target="(blank && '_blank') || target">
<UButton :variant="variant" :size="size" :icon="icon" :trailing-icon="trailingIcon" class="min-h-10 max-h-12">
<slot/>
</UButton>
</NuxtLink>
</div>
<NuxtLink
:to="to || href"
:target="(blank && '_blank') || target"
>
<UButton
:variant="variant"
:size="size"
:icon="icon"
:trailing-icon="trailingIcon"
class="min-h-10 max-h-12"
>
<slot />
</UButton>
</NuxtLink>
</div>
</template>
<script setup lang="ts">
type Target = '_blank' | '_parent' | '_self' | '_top' | (string & object) | null | undefined;
type Target = '_blank' | '_parent' | '_self' | '_top' | (string & object) | null | undefined
defineProps<{
variant?: 'solid' | 'outline' | 'ghost' | 'link' | 'soft';
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
color?: 'gray' | 'red' | 'orange' | 'amber' | 'yellow' | 'lime' | 'green' | 'emerald' | 'teal' | 'cyan' | 'sky' | 'blue' | 'indigo' | 'violet' | 'purple' | 'fuchsia' | 'pink' | 'rose' | 'white' | 'black';
icon?: string;
to?: string;
href?: string;
target?: Target;
trailingIcon?: string;
blank?: boolean;
}>();
variant?: 'solid' | 'outline' | 'ghost' | 'link' | 'soft'
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
color?: 'gray' | 'red' | 'orange' | 'amber' | 'yellow' | 'lime' | 'green' | 'emerald' | 'teal' | 'cyan' | 'sky' | 'blue' | 'indigo' | 'violet' | 'purple' | 'fuchsia' | 'pink' | 'rose' | 'white' | 'black'
icon?: string
to?: string
href?: string
target?: Target
trailingIcon?: string
blank?: boolean
}>()
</script>

View File

@@ -7,7 +7,7 @@ const isLight = computed({
},
set(_isLight) {
colorMode.preference = _isLight ? 'light' : 'dark'
},
}
})
</script>
@@ -24,7 +24,7 @@ const isLight = computed({
:ui="{
base: 'w-70 h-35 rounded-lg rotate-90 data-[state=checked]:bg-[var(--ui-color-neutral-200)]',
thumb: 'data-[state=checked]:translate-x-35 data-[state=checked]:rtl:-translate-x-35 rounded-lg size-34',
icon: 'rotate-270 size-8',
icon: 'rotate-270 size-8'
}"
@click="isDark = !isDark"
/>

View File

@@ -1,14 +1,19 @@
<template>
<UPageCard :title="title" :description="description" :spotlight="spotlight" :icon="icon" class="">
<slot/>
<NuxtImg
v-if="img"
:src="img"
class="w-full"
/>
<span> {{ content }} </span>
</UPageCard>
<UPageCard
:title="title"
:description="description"
:spotlight="spotlight"
:icon="icon"
class=""
>
<slot />
<NuxtImg
v-if="img"
:src="img"
class="w-full"
/>
<span> {{ content }} </span>
</UPageCard>
</template>
<!-- ::card
@@ -21,20 +26,18 @@ Image Card
#content
Beautifully designed **Nuxt Content** template with **shadcn-vue**. _Customizable. Compatible. Open Source._
:: -->
<script setup lang="ts">
const {
content="",
<script setup lang="ts">
const {
content = ''
} =defineProps<{
title?: string;
content?: string;
img?: string;
icon?: string;
description?: string;
spotlight?:boolean;
slot?:string;
}>();
</script>
} = defineProps<{
title?: string
content?: string
img?: string
icon?: string
description?: string
spotlight?: boolean
slot?: string
}>()
</script>

View File

@@ -1,6 +1,14 @@
<template>
<UTabs :items="tabItems" class="w-full" :unmount-on-hide="false" variant="link">
<template v-for="item in tabItems" #[item.slot]="{ item: slotItem }">
<UTabs
:items="tabItems"
class="w-full"
:unmount-on-hide="false"
variant="link"
>
<template
v-for="item in tabItems"
#[item.slot]="{ item: slotItem }"
>
<div class="mt-4">
<component :is="getSlotContent(slotItem)" />
</div>
@@ -38,4 +46,4 @@ function getSlotContent(item: TabsItem) {
if (!item.slot) return null
return slotContents.value[item.slot]
}
</script>
</script>

View File

@@ -1,9 +1,16 @@
<template>
<UPage class="mt-4 mb-4 bg-white dark:bg-gray-900 rounded-xl border border-gray-300 dark:border-gray-700">
<div v-if="title" class="flex items-center font-mono text-base m-3 text-gray-700 dark:text-gray-300 rounded-xl ">
<Icon v-if="icon" :name="icon" class="mr-2" size="20" />
<div
v-if="title"
class="flex items-center font-mono text-base m-3 text-gray-700 dark:text-gray-300 rounded-xl "
>
<Icon
v-if="icon"
:name="icon"
class="mr-2"
size="20"
/>
<span>{{ title }}</span>
</div>
@@ -23,7 +30,7 @@
/>
</div>
</div>
<!-- 服务端渲染时的占位符 -->
<template #fallback>
<div class="space-y-1">
@@ -33,8 +40,11 @@
class="file-tree-item"
>
<div class="flex items-center py-1 px-2">
<div class="flex items-center" :style="{ marginLeft: '0px' }">
<Icon
<div
class="flex items-center"
:style="{ marginLeft: '0px' }"
>
<Icon
v-if="showIcon"
:name="item.icon || 'lucide-file'"
class="mr-2 text-gray-500 w-4 h-4"
@@ -45,7 +55,7 @@
'text-yellow-500': item.icon?.includes('json')
}"
/>
<span
<span
class="text-sm font-mono"
:class="{
'font-semibold': item.isFolder,
@@ -61,38 +71,38 @@
</template>
</ClientOnly>
</div>
</UPage>
</UPage>
</template>
<script setup lang="ts">
type InputTreeItem = string | {
[key: string]: InputTreeItem[];
};
[key: string]: InputTreeItem[]
}
type FileTreeItemDiff = 'none' | 'addition' | 'deletion';
type FileTreeItemDiff = 'none' | 'addition' | 'deletion'
interface FileTreeItem {
title: string;
icon?: string;
children?: FileTreeItem[];
highlighted?: boolean;
diff?: FileTreeItemDiff;
isFolder?: boolean;
title: string
icon?: string
children?: FileTreeItem[]
highlighted?: boolean
diff?: FileTreeItemDiff
isFolder?: boolean
}
const {
tree,
autoSlash = true,
showArrow = false,
showIcon = true,
showIcon = true
} = defineProps<{
title?: string;
icon?: string;
autoSlash?: boolean;
showArrow?: boolean;
showIcon?: boolean;
tree: InputTreeItem[];
}>();
title?: string
icon?: string
autoSlash?: boolean
showArrow?: boolean
showIcon?: boolean
tree: InputTreeItem[]
}>()
// 默认图标映射
const defaultIcons = {
@@ -103,38 +113,38 @@ const defaultIcons = {
json: 'simple-icons-json',
folder: 'lucide-folder',
file: 'lucide-file'
};
}
function getIcon(filename: string, type: 'folder' | 'file'): string {
if (filename === '...') return 'lucide-more-horizontal';
if (filename.endsWith('/')) return defaultIcons.folder;
if (filename === '...') return 'lucide-more-horizontal'
if (filename.endsWith('/')) return defaultIcons.folder
const parts = filename.split('.')
const extension = parts.length > 1 ? parts[parts.length - 1]?.toLowerCase() || '' : ''
const parts = filename.split('.');
const extension = parts.length > 1 ? parts[parts.length - 1]?.toLowerCase() || '' : '';
// 根据扩展名返回对应图标
switch (extension) {
case 'vue': return defaultIcons.vue;
case 'ts': return defaultIcons.ts;
case 'js': return defaultIcons.js;
case 'md': return defaultIcons.md;
case 'json': return defaultIcons.json;
default: return type === 'file' ? defaultIcons.file : defaultIcons.folder;
case 'vue': return defaultIcons.vue
case 'ts': return defaultIcons.ts
case 'js': return defaultIcons.js
case 'md': return defaultIcons.md
case 'json': return defaultIcons.json
default: return type === 'file' ? defaultIcons.file : defaultIcons.folder
}
}
function getItem(key: string, type: 'folder' | 'file', children?: InputTreeItem[]): FileTreeItem {
let title = key;
let highlighted = false;
let title = key
let highlighted = false
if (title.startsWith('^') && title.endsWith('^')) {
title = title.substring(1, title.length - 1);
highlighted = true;
title = title.substring(1, title.length - 1)
highlighted = true
}
let diff: FileTreeItemDiff = 'none';
if (title.startsWith('+')) diff = 'addition';
else if (title.startsWith('-')) diff = 'deletion';
let diff: FileTreeItemDiff = 'none'
if (title.startsWith('+')) diff = 'addition'
else if (title.startsWith('-')) diff = 'deletion'
if (type === 'file') {
return {
@@ -143,7 +153,7 @@ function getItem(key: string, type: 'folder' | 'file', children?: InputTreeItem[
highlighted,
diff,
isFolder: false
};
}
} else {
return {
title: `${title}${autoSlash ? '/' : ''}`,
@@ -152,35 +162,35 @@ function getItem(key: string, type: 'folder' | 'file', children?: InputTreeItem[
highlighted,
diff,
isFolder: true
};
}
}
}
function getTree(tree: InputTreeItem[]): FileTreeItem[] {
const res: FileTreeItem[] = [];
const res: FileTreeItem[] = []
for (const item of tree) {
if (typeof item === 'string') {
res.push(getItem(item, 'file'));
res.push(getItem(item, 'file'))
} else if (typeof item === 'object' && item !== null) {
for (const key of Object.keys(item)) {
const children = (item as Record<string, InputTreeItem[]>)[key];
const children = (item as Record<string, InputTreeItem[]>)[key]
if (children) {
res.push(getItem(key, 'folder', children));
res.push(getItem(key, 'folder', children))
}
}
}
}
return res;
return res
}
const parsedTree = computed(() => {
return getTree(tree);
});
return getTree(tree)
})
// 使用 provide/inject 来管理展开状态
const expandedState = ref(new Set<string>());
const expandedState = ref(new Set<string>())
provide('expandedState', expandedState);
provide('expandedState', expandedState)
</script>

View File

@@ -1,6 +1,6 @@
<template>
<div class="file-tree-item">
<div
<div
class="flex items-center py-1 px-2 rounded hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors"
:class="{
'bg-blue-50 dark:bg-blue-900/20': item.highlighted,
@@ -10,18 +10,24 @@
@click="toggleFolder"
>
<!-- 缩进 -->
<div class="flex items-center" :style="{ marginLeft: level * 16 + 'px' }">
<div
class="flex items-center"
:style="{ marginLeft: level * 16 + 'px' }"
>
<!-- 箭头仅文件夹且有子项时显示 -->
<Icon
<Icon
v-if="showArrow && item.isFolder && item.children && item.children.length > 0"
:name="isExpanded ? 'lucide-chevron-down' : 'lucide-chevron-right'"
class="mr-1 text-gray-400 w-4 h-4 transition-transform"
:class="{ 'rotate-90': isExpanded }"
/>
<div v-else-if="showArrow" class="w-4 mr-1"></div>
<div
v-else-if="showArrow"
class="w-4 mr-1"
/>
<!-- 图标 -->
<Icon
<Icon
v-if="showIcon"
:name="item.icon || 'lucide-file'"
class="mr-2 text-gray-500 w-4 h-4"
@@ -32,9 +38,9 @@
'text-yellow-500': item.icon?.includes('json')
}"
/>
<!-- 标题 -->
<span
<span
class="text-sm font-mono"
:class="{
'font-semibold': item.isFolder,
@@ -47,7 +53,10 @@
</div>
<!-- 子项 -->
<div v-if="item.children && item.children.length > 0 && isExpanded" class="ml-4">
<div
v-if="item.children && item.children.length > 0 && isExpanded"
class="ml-4"
>
<FileTreeItem
v-for="child in item.children"
:key="child.title"
@@ -61,48 +70,48 @@
</template>
<script setup lang="ts">
type FileTreeItemDiff = 'none' | 'addition' | 'deletion';
type FileTreeItemDiff = 'none' | 'addition' | 'deletion'
interface FileTreeItem {
title: string;
icon?: string;
children?: FileTreeItem[];
highlighted?: boolean;
diff?: FileTreeItemDiff;
isFolder?: boolean;
title: string
icon?: string
children?: FileTreeItem[]
highlighted?: boolean
diff?: FileTreeItemDiff
isFolder?: boolean
}
const props = defineProps<{
item: FileTreeItem;
level: number;
showArrow: boolean;
showIcon: boolean;
}>();
item: FileTreeItem
level: number
showArrow: boolean
showIcon: boolean
}>()
const expandedState = inject('expandedState', ref(new Set<string>()));
const itemKey = computed(() => `${props.item.title}-${props.level}`);
const expandedState = inject('expandedState', ref(new Set<string>()))
const itemKey = computed(() => `${props.item.title}-${props.level}`)
const isExpanded = computed({
get: () => expandedState.value.has(itemKey.value),
set: (value: boolean) => {
if (value) {
expandedState.value.add(itemKey.value);
expandedState.value.add(itemKey.value)
} else {
expandedState.value.delete(itemKey.value);
expandedState.value.delete(itemKey.value)
}
}
});
})
// 初始化时展开所有文件夹
onMounted(() => {
if (props.item.isFolder && props.item.children && props.item.children.length > 0) {
isExpanded.value = true;
isExpanded.value = true
}
});
})
function toggleFolder() {
if (props.item.isFolder && props.item.children && props.item.children.length > 0) {
isExpanded.value = !isExpanded.value;
isExpanded.value = !isExpanded.value
}
}
</script>
</script>

View File

@@ -7,7 +7,10 @@
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
class="w-full h-full min-h-[600px] overflow-hidden rounded-md"
/>
<USkeleton v-else class="w-full min-h-[600px] rounded-md" />
<USkeleton
v-else
class="w-full min-h-[600px] rounded-md"
/>
</div>
</template>
@@ -19,31 +22,31 @@ const {
branch = 'main',
dir = '',
file,
title = 'Playground',
title = 'Playground'
} = defineProps<{
provider: 'stackblitz' | 'codesandbox';
id?: string;
repo?: string;
branch?: string;
dir?: string;
file: string;
title?: string;
}>();
provider: 'stackblitz' | 'codesandbox'
id?: string
repo?: string
branch?: string
dir?: string
file: string
title?: string
}>()
const url = ref('');
const colorMode = useColorMode();
const url = ref('')
const colorMode = useColorMode()
onMounted(() => {
if (provider === 'stackblitz') {
if (repo)
url.value = `https://stackblitz.com/github/${repo}/tree/${branch}/${dir}?embed=1&file=${file}&theme=${colorMode.value}`;
url.value = `https://stackblitz.com/github/${repo}/tree/${branch}/${dir}?embed=1&file=${file}&theme=${colorMode.value}`
else if (id)
url.value = `https://stackblitz.com/edit/${id}?embed=1&file=${file}&theme=${colorMode.value}`;
url.value = `https://stackblitz.com/edit/${id}?embed=1&file=${file}&theme=${colorMode.value}`
} else if (provider === 'codesandbox') {
if (repo)
url.value = `https://codesandbox.io/p/sandbox/github/${repo}/tree/${branch}/${dir}?embed=1&file=${file}`;
url.value = `https://codesandbox.io/p/sandbox/github/${repo}/tree/${branch}/${dir}?embed=1&file=${file}`
else if (id)
url.value = `https://codesandbox.io/embed/${id}?view=editor+%2B+preview&module=${file}`;
url.value = `https://codesandbox.io/embed/${id}?view=editor+%2B+preview&module=${file}`
}
});
})
</script>

View File

@@ -1,5 +1,8 @@
<template>
<h1 :id class="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
<h1
:id
class="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl"
>
<NuxtLink
v-if="generate"
:to="`#${id}`"
@@ -11,8 +14,8 @@
</template>
<script setup lang="ts">
const { id } = defineProps<{ id?: string }>();
const { id } = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc;
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h1)));
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h1)))
</script>

View File

@@ -1,5 +1,8 @@
<template>
<h2 :id class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors [&:not(:first-child)]:mt-10">
<h2
:id
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors [&:not(:first-child)]:mt-10"
>
<NuxtLink
v-if="id && generate"
:to="`#${id}`"
@@ -11,8 +14,8 @@
</template>
<script setup lang="ts">
const { id } = defineProps<{ id?: string }>();
const { id } = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc;
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h2)));
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h2)))
</script>

View File

@@ -1,5 +1,8 @@
<template>
<h3 :id class="scroll-m-20 text-2xl font-semibold tracking-tight [&:not(:first-child)]:mt-8">
<h3
:id
class="scroll-m-20 text-2xl font-semibold tracking-tight [&:not(:first-child)]:mt-8"
>
<NuxtLink
v-if="id && generate"
:to="`#${id}`"
@@ -11,8 +14,8 @@
</template>
<script setup lang="ts">
const { id } = defineProps<{ id?: string }>();
const { id } = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc;
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h3)));
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h3)))
</script>

View File

@@ -1,5 +1,8 @@
<template>
<h4 :id class="scroll-m-20 text-xl font-semibold tracking-tight [&:not(:first-child)]:mt-6">
<h4
:id
class="scroll-m-20 text-xl font-semibold tracking-tight [&:not(:first-child)]:mt-6"
>
<NuxtLink
v-if="id && generate"
:to="`#${id}`"
@@ -11,8 +14,8 @@
</template>
<script setup lang="ts">
const { id } = defineProps<{ id?: string }>();
const { id } = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc;
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h4)));
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h4)))
</script>

View File

@@ -1,5 +1,8 @@
<template>
<h5 :id class="scroll-m-20 text-lg font-semibold tracking-tight [&:not(:first-child)]:mt-6">
<h5
:id
class="scroll-m-20 text-lg font-semibold tracking-tight [&:not(:first-child)]:mt-6"
>
<NuxtLink
v-if="id && generate"
:to="`#${id}`"
@@ -11,8 +14,8 @@
</template>
<script setup lang="ts">
const { id } = defineProps<{ id?: string }>();
const { id } = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc;
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h5)));
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h5)))
</script>

View File

@@ -1,5 +1,8 @@
<template>
<h6 :id class="scroll-m-20 text-lg font-semibold tracking-tight [&:not(:first-child)]:mt-6">
<h6
:id
class="scroll-m-20 text-lg font-semibold tracking-tight [&:not(:first-child)]:mt-6"
>
<NuxtLink
v-if="id && generate"
:to="`#${id}`"
@@ -11,8 +14,8 @@
</template>
<script setup lang="ts">
const { id } = defineProps<{ id?: string }>();
const { id } = defineProps<{ id?: string }>()
const { headings } = useRuntimeConfig().public.mdc;
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h6)));
const { headings } = useRuntimeConfig().public.mdc
const generate = computed(() => id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h6)))
</script>

View File

@@ -1,10 +1,20 @@
<template>
<UPage>
<NuxtLink v-if="to" :to="to">
<UAlert :icon :title :color="color" :variant="variant" :description="to"
class="mt-2 mb-3 text-black dark:text-white" :ui="{
<NuxtLink
v-if="to"
:to="to"
>
<UAlert
:icon
:title
:color="color"
:variant="variant"
:description="to"
class="mt-2 mb-3 text-black dark:text-white"
:ui="{
icon: iconSize
}">
}"
>
<slot />
</UAlert>
</NuxtLink>
@@ -12,20 +22,18 @@
</template>
<script setup lang="ts">
const {
variant = 'subtle',
title,
icon = 'lucide:bookmark',
color = 'primary',
color = 'primary'
} = defineProps<{
color?: 'primary' | 'error' | 'secondary' | 'success' | 'info' | 'warning' | 'neutral';
description?: string;
title?: string;
to?: string;
icon?: string;
iconSize?: string;
variant?: 'subtle' | 'solid' | 'outline' | 'soft';
}>();
color?: 'primary' | 'error' | 'secondary' | 'success' | 'info' | 'warning' | 'neutral'
description?: string
title?: string
to?: string
icon?: string
iconSize?: string
variant?: 'subtle' | 'solid' | 'outline' | 'soft'
}>()
</script>

View File

@@ -1,6 +1,10 @@
<template>
<!-- Iconify Icons -->
<Icon v-if="checkIcon(name)" :name :size />
<Icon
v-if="checkIcon(name)"
:name
:size
/>
<!-- Emojis -->
<span
v-else-if="/(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g.test(name)"
@@ -16,17 +20,17 @@
</template>
<script setup lang="ts">
import { stringToIcon, validateIconName } from '@iconify/utils';
import { stringToIcon, validateIconName } from '@iconify/utils'
const { size = 16 } = defineProps<{
name: string;
size?: number;
}>();
name: string
size?: number
}>()
function checkIcon(name: string): boolean {
if (name.includes('http'))
return false;
return false
return validateIconName(stringToIcon(name));
return validateIconName(stringToIcon(name))
}
</script>

View File

@@ -1,13 +1,12 @@
<template>
<UPageCard class="divide-y overflow-hidden rounded-xl [&:not(:first-child)]:mt-4 dark:divide-gray-700 shadow-sm ">
<div
v-for="(slot, i) in slotItems"
:key="i"
class=""
>
<component :is="slot" />
</div>
<div
v-for="(slot, i) in slotItems"
:key="i"
class=""
>
<component :is="slot" />
</div>
</UPageCard>
</template>

View File

@@ -1,11 +1,12 @@
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'
const route = useRoute()
const items = ref<NavigationMenuItem[][]>([
[
{
label: 'Guide',
icon: 'lucide-book-open',
icon: 'lucide-book-open'
},
{
label: 'Composables',
@@ -74,7 +75,7 @@ const items = ref<NavigationMenuItem[][]>([
}
]
}
],
]
// [
// {
// label: 'GitHub',
@@ -94,5 +95,10 @@ const items = ref<NavigationMenuItem[][]>([
</script>
<template>
<UNavigationMenu orientation="vertical" :items="items" class="w-full justify-center" color="primary" />
<UNavigationMenu
orientation="vertical"
:items="items"
class="w-full justify-center"
color="primary"
/>
</template>

View File

@@ -17,28 +17,28 @@ const items = [
toast.add({
title: 'Markdown link copied to clipboard',
icon: 'lucide-check-circle',
color: 'success',
color: 'success'
})
},
}
},
{
label: 'View as Markdown',
icon: 'simple-icons:markdown',
target: '_blank',
to: markdownLink.value,
to: markdownLink.value
},
{
label: 'Open in ChatGPT',
icon: 'simple-icons:openai',
target: '_blank',
to: `https://chatgpt.com/?hints=search&q=${encodeURIComponent(`Read ${markdownLink.value} so I can ask questions about it.`)}`,
to: `https://chatgpt.com/?hints=search&q=${encodeURIComponent(`Read ${markdownLink.value} so I can ask questions about it.`)}`
},
{
label: 'Open in Claude',
icon: 'simple-icons:anthropic',
target: '_blank',
to: `https://claude.ai/new?q=${encodeURIComponent(`Read ${markdownLink.value} so I can ask questions about it.`)}`,
},
to: `https://claude.ai/new?q=${encodeURIComponent(`Read ${markdownLink.value} so I can ask questions about it.`)}`
}
]
</script>
@@ -50,7 +50,7 @@ const items = [
color="neutral"
variant="outline"
:ui="{
leadingIcon: [copied ? 'text-primary' : 'text-neutral', 'size-3.5'],
leadingIcon: [copied ? 'text-primary' : 'text-neutral', 'size-3.5']
}"
@click="copy(markdownLink)"
/>
@@ -61,10 +61,10 @@ const items = [
:content="{
align: 'end',
side: 'bottom',
sideOffset: 8,
sideOffset: 8
}"
:ui="{
content: 'w-48',
content: 'w-48'
}"
>
<UButton