Add title to every pages + new pull/push jobs + DropdownMenu

This commit is contained in:
2024-11-13 13:41:32 +01:00
parent b54402fc19
commit ac17134b7e
13 changed files with 237 additions and 88 deletions

View 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>

View 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>

View File

@@ -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>