diff --git a/app.config.ts b/app.config.ts index 5bb52ee..5d95658 100644 --- a/app.config.ts +++ b/app.config.ts @@ -1,8 +1,9 @@ import navs from '~/config/navs' -import type { AppConfig } from '~/types/app-config' -export default defineAppConfig({ - navs: navs, - name: process.env.APP_NAME || 'RustFS', - description: process.env.APP_DESCRIPTION || 'RustFS is a distributed file system written in Rust.', +export default defineAppConfig({ + navs, + icon: { + mode: 'css', + cssLayer: 'base', + }, }) diff --git a/components/app-sidebar.vue b/components/app-sidebar.vue index b8ab697..0e0d074 100644 --- a/components/app-sidebar.vue +++ b/components/app-sidebar.vue @@ -22,15 +22,16 @@ import { import { computed } from 'vue' import { useI18n } from 'vue-i18n' import { useRoute } from 'vue-router' -import type { AppConfig, NavItem } from '~/types/app-config' +import type { NavItem } from '~/types/app-config' -const appConfig = useAppConfig() as unknown as AppConfig +const appConfig = useAppConfig() +const config = useRuntimeConfig() const route = useRoute() const { t } = useI18n() const { state } = useSidebar() const { isAdmin, canAccessPath } = usePermissions() const isCollapsed = computed(() => state.value === 'collapsed') -const brandInitial = computed(() => appConfig.name?.charAt(0)?.toUpperCase() ?? 'R') +const brandInitial = computed(() => config.public.appName.charAt(0).toUpperCase() ?? 'R') const navGroups = computed(() => { const groups: NavItem[][] = [] @@ -42,11 +43,11 @@ const navGroups = computed(() => { if (nav.children?.length) { visibleChildren = nav.children.filter(child => { if (child.to && !canAccessPath(child.to)) return false - + // If child is admin only and user is not admin, but has permission (checked above), allow it. // If child has no path (unlikely for leaf) and is admin only, hide it. if (child.isAdminOnly && !isAdmin.value && !child.to) return false - + return true }) @@ -59,10 +60,10 @@ const navGroups = computed(() => { if (nav.to && !canAccessPath(nav.to)) { continue } - + // If no path and no children (e.g. divider), check isAdminOnly if (!nav.to && nav.isAdminOnly && !isAdmin.value) { - continue + continue } } diff --git a/components/copy-input.vue b/components/copy-input.vue index f9a5d71..8421a22 100644 --- a/components/copy-input.vue +++ b/components/copy-input.vue @@ -4,8 +4,6 @@ import { Input } from '@/components/ui/input' import { Icon } from '#components' import { useMessage } from '@/lib/ui/message' -import ClipboardJS from 'clipboard' -import { onMounted, onUnmounted, ref } from 'vue' import { useI18n } from 'vue-i18n' const { t } = useI18n() @@ -31,50 +29,41 @@ const props = defineProps({ const model = defineModel() const message = useMessage() -const clipboard = ref(null) -onMounted(() => { - clipboard.value = new ClipboardJS(props.copyIcon ? `#${props.id}-btn-icon` : `#${props.id}-btn`) +const { copy } = useClipboard() + +async function handleCopyGeneratedUrl() { + try { + if (!model.value) throw new Error('No value to copy') + + await copy(model.value) - clipboard.value.on('success', function (e) { message.success(t('Copy Success')) - e.clearSelection() - }) - - clipboard.value.on('error', async function () { - // If copy fails, use navigator.clipboard.writeText as fallback - try { - if (navigator.clipboard && model.value) { - await navigator.clipboard.writeText(model.value) - message.success(t('Copy Success')) - } else { - message.error(t('Copy Failed')) - } - } catch { - message.error(t('Copy Failed')) - } - }) -}) - -onUnmounted(() => { - clipboard.value?.destroy() - clipboard.value = null -}) + } catch (error) { + message.error(t('Copy Failed')) + } +}