You've already forked obsidian-visualiser
Add title to every pages + new pull/push jobs + DropdownMenu
This commit is contained in:
66
components/base/DropdownContentRender.vue
Normal file
66
components/base/DropdownContentRender.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<template v-for="(item, idx) of options">
|
||||
<template v-if="item.type === 'item'">
|
||||
<DropdownMenuItem :disabled="item.disabled" :textValue="item.label" @select="item.select">
|
||||
<Icon v-if="item.icon" :icon="item.icon" />
|
||||
<span>{{ item.label }}</span>
|
||||
<span v-if="item.kbd"> {{ item.kbd }} </span>
|
||||
</DropdownMenuItem>
|
||||
</template>
|
||||
|
||||
<template v-else-if="item.type === 'checkbox'">
|
||||
<DropdownMenuCheckboxItem :disabled="item.disabled" :textValue="item.label" @update:checked="item.select">
|
||||
<DropdownMenuItemIndicator>
|
||||
<Icon icon="radix-icons:check" />
|
||||
</DropdownMenuItemIndicator>
|
||||
<span>{{ item.label }}</span>
|
||||
<span v-if="item.kbd"> {{ item.kbd }} </span>
|
||||
</DropdownMenuCheckboxItem>
|
||||
</template>
|
||||
|
||||
<template v-if="item.type === 'radio'">
|
||||
<DropdownMenuLabel>{{ item.label }}</DropdownMenuLabel>
|
||||
<DropdownMenuRadioGroup @update:model-value="item.change">
|
||||
<DropdownMenuRadioItem v-for="option in item.items" :disabled="(option as any)?.disabled ?? false" :value="(option as any)?.value ?? option">
|
||||
<DropdownMenuItemIndicator>
|
||||
<Icon icon="radix-icons:dot-filled" />
|
||||
</DropdownMenuItemIndicator>
|
||||
<span>{{ (option as any)?.label || option }}</span>
|
||||
</DropdownMenuRadioItem>
|
||||
</DropdownMenuRadioGroup>
|
||||
|
||||
<DropdownMenuSeparator v-if="idx !== options.length - 1" />
|
||||
</template>
|
||||
|
||||
<template v-if="item.type === 'submenu'">
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<Icon v-if="item.icon" :icon="item.icon" />
|
||||
<span>{{ item.label }}</span>
|
||||
<Icon icon="radix-icons:chevron-right" />
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownContentRender :options="item.items" />
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
</template>
|
||||
|
||||
<template v-if="item.type === 'group'">
|
||||
<DropdownMenuLabel>{{ item.label }}</DropdownMenuLabel>
|
||||
<DropdownContetnRender :options="item.items" />
|
||||
|
||||
<DropdownMenuSeparator v-if="idx !== options.length - 1" />
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DropdownOption } from './DropdownMenu.vue';
|
||||
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||
|
||||
const { options } = defineProps<{
|
||||
options: DropdownOption[]
|
||||
}>();
|
||||
</script>
|
||||
59
components/base/DropdownMenu.vue
Normal file
59
components/base/DropdownMenu.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<DropdownMenuRoot>
|
||||
<DropdownMenuTrigger :disabled="disabled" ><slot /></DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuContent :align="align" :side="side">
|
||||
<DropdownContentRender :options="options" />
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuArrow />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuRoot>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
export interface DropdownItem {
|
||||
type: 'item';
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
select?: () => void;
|
||||
icon?: string;
|
||||
kbd?: string;
|
||||
}
|
||||
export interface DropdownCheckbox {
|
||||
type: 'checkbox';
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
checked?: boolean | Ref<boolean>
|
||||
select?: (state: boolean) => void;
|
||||
kbd?: string;
|
||||
}
|
||||
export interface DropdownRadioGroup {
|
||||
type: 'radio';
|
||||
label: string;
|
||||
value?: string | Ref<string>
|
||||
items: (string | {label: string, value?: string, disabled?: boolean})[];
|
||||
change?: (value: string) => void;
|
||||
}
|
||||
export interface DropdownSubmenu {
|
||||
type: 'submenu';
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
items: DropdownOption[];
|
||||
icon?: string;
|
||||
}
|
||||
export interface DropdownGroup {
|
||||
type: 'group';
|
||||
label?: string;
|
||||
items: DropdownOption[];
|
||||
}
|
||||
export type DropdownOption = DropdownItem | DropdownCheckbox | DropdownRadioGroup | DropdownSubmenu | DropdownGroup;
|
||||
const { options, disabled = false, side, align } = defineProps<{
|
||||
options: DropdownOption[]
|
||||
disabled?: boolean
|
||||
side?: 'top' | 'right' | 'bottom' | 'left'
|
||||
align?: 'start' | 'center' | 'end'
|
||||
}>();
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<TreeRoot v-slot="{ flattenItems }" class="list-none select-none text-light-100 dark:text-dark-100 p-2 xl:text-base text-sm" :items="model" :get-key="(item) => item.link ?? item.label">
|
||||
<TreeRoot v-slot="{ flattenItems }" class="list-none select-none text-light-100 dark:text-dark-100 p-2 xl:text-base text-sm" :items="model" :get-key="(item) => item.link ?? item.label" :defaultExpanded="flatten(model)">
|
||||
<TreeItem v-for="item in flattenItems" v-slot="{ isExpanded }" :key="item._id" :style="{ 'padding-left': `${item.level - 0.5}em` }" v-bind="item.bind" class="flex items-center px-2 outline-none relative cursor-pointer">
|
||||
<NuxtLink :href="item.value.link && !item.hasChildren ? { name: 'explore-path', params: { path: item.value.link } } : undefined" no-prefetch class="flex flex-1 items-center border-light-35 dark:border-dark-35 hover:border-accent-blue" :class="{ 'border-s': !item.hasChildren, 'font-medium': item.hasChildren }" active-class="text-accent-blue border-s-2 !border-accent-blue">
|
||||
<Icon v-if="item.hasChildren" icon="radix-icons:chevron-right" :class="{ 'rotate-90': isExpanded }" class="h-4 w-4 transition-transform absolute" :style="{ 'left': `${item.level - 1}em` }" />
|
||||
@@ -19,9 +19,15 @@ interface TreeItem
|
||||
label: string
|
||||
link?: string
|
||||
tag?: string
|
||||
open?: boolean
|
||||
children?: TreeItem[]
|
||||
}
|
||||
const model = defineModel<TreeItem[]>();
|
||||
|
||||
function flatten(arr: TreeItem[]): string[]
|
||||
{
|
||||
return arr.filter(e => e.open).flatMap(e => [e?.link ?? e.label, ...flatten(e.children ?? [])]);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user