refactor to UI components
This commit is contained in:
4
components.d.ts
vendored
4
components.d.ts
vendored
@@ -31,10 +31,14 @@ declare module '@vue/runtime-core' {
|
||||
Spinner: typeof import('./src/components/Spinner.vue')['default']
|
||||
TopBar: typeof import('./src/components/TopBar.vue')['default']
|
||||
UIAlert: typeof import('./src/components/ui/UIAlert.vue')['default']
|
||||
UIBadge: typeof import('./src/components/ui/UIBadge.vue')['default']
|
||||
UIButton: typeof import('./src/components/ui/UIButton.vue')['default']
|
||||
UIButtonGroup: typeof import('./src/components/ui/UIButtonGroup.vue')['default']
|
||||
UICard: typeof import('./src/components/ui/UICard.vue')['default']
|
||||
UIDropdown: typeof import('./src/components/ui/UIDropdown.vue')['default']
|
||||
UIDropdownItem: typeof import('./src/components/ui/UIDropdownItem.vue')['default']
|
||||
UIMenu: typeof import('./src/components/ui/UIMenu.vue')['default']
|
||||
UIMenuItem: typeof import('./src/components/ui/UIMenuItem.vue')['default']
|
||||
UIModal: typeof import('./src/components/ui/UIModal.vue')['default']
|
||||
UITable: typeof import('./src/components/ui/UITable.vue')['default']
|
||||
UITextInput: typeof import('./src/components/ui/UITextInput.vue')['default']
|
||||
|
||||
@@ -45,16 +45,11 @@ const handleKeypress = (event: { [key: string]: number }) => {
|
||||
defineExpose({ handleKeypress })
|
||||
</script>
|
||||
<template>
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="menu rounded-md border-[1px] bg-base-100 p-2 text-[0.875rem] text-black shadow-md"
|
||||
>
|
||||
<li class="flex flex-row" @click="emit('createLink', props.autocompleteText)">
|
||||
<a class="flex-grow px-2 py-1" :class="!activeResult && 'active'">
|
||||
<span class="flex-grow">{{ props.autocompleteText }}</span>
|
||||
<i class="fas fa-plus-circle ml-auto text-white" />
|
||||
</a>
|
||||
</li>
|
||||
<UIMenu class="border-[1px] p-2 text-[0.875rem] text-black shadow-md" :compact="true">
|
||||
<UIMenuItem :active="!activeResult" @click="emit('createLink', props.autocompleteText)">
|
||||
<span class="flex-grow">{{ props.autocompleteText }}</span>
|
||||
<i class="fas fa-plus-circle ml-auto text-white" />
|
||||
</UIMenuItem>
|
||||
<SearchResult
|
||||
v-for="result in results"
|
||||
:key="result.id"
|
||||
@@ -62,5 +57,5 @@ defineExpose({ handleKeypress })
|
||||
:active-result="activeResult"
|
||||
@go-to-note="emit('createLink', result.title)"
|
||||
/>
|
||||
</ul>
|
||||
</UIMenu>
|
||||
</template>
|
||||
|
||||
@@ -5,22 +5,18 @@ const props = defineProps<{
|
||||
}>()
|
||||
</script>
|
||||
<template>
|
||||
<div class="card mt-3 border-[1px]" v-if="props.references.length > 0">
|
||||
<div class="card-body px-3 py-3">
|
||||
<ul class="menu rounded-md">
|
||||
<li class="menu-title !opacity-100">
|
||||
<span class="card-title text-secondary">
|
||||
References
|
||||
<div class="badge-outline badge">{{ props.references.length }}</div>
|
||||
</span>
|
||||
</li>
|
||||
<li v-for="reference in props.references" :key="reference.id">
|
||||
<a class="rounded-md" @click="setActiveNote(reference.id)">
|
||||
<i class="far fa-file-alt fa-fw" />
|
||||
{{ reference.title }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<UIMenu class="mt-3 rounded-xl border-[1px] px-3 py-3" v-if="props.references.length > 0">
|
||||
<UIMenuItem :title="true">
|
||||
<span>References</span>
|
||||
<UIBadge variant="outline">{{ props.references.length }}</UIBadge>
|
||||
</UIMenuItem>
|
||||
<UIMenuItem
|
||||
v-for="reference in props.references"
|
||||
:key="reference.id"
|
||||
@click="setActiveNote(reference.id)"
|
||||
>
|
||||
<i class="far fa-file-alt fa-fw" />
|
||||
{{ reference.title }}
|
||||
</UIMenuItem>
|
||||
</UIMenu>
|
||||
</template>
|
||||
|
||||
@@ -66,7 +66,7 @@ const resultsRefs = ref<InstanceType<typeof SearchResult>[]>([])
|
||||
@keydown="handleKeydown"
|
||||
/>
|
||||
<div class="z-1000 absolute left-0 right-0 top-[100%]" v-if="active">
|
||||
<ul tabindex="0" class="menu mt-1 w-full rounded-md bg-base-100 p-2 text-black shadow">
|
||||
<UIMenu :compact="true" class="mt-1 w-full rounded-md bg-base-100 p-2 text-black shadow">
|
||||
<div class="max-h-[320px] w-full overflow-y-auto">
|
||||
<template v-if="results.length > 0">
|
||||
<SearchResult
|
||||
@@ -78,9 +78,9 @@ const resultsRefs = ref<InstanceType<typeof SearchResult>[]>([])
|
||||
ref="resultsRefs"
|
||||
/>
|
||||
</template>
|
||||
<li v-else><a>No notes found</a></li>
|
||||
<UIMenuItem :compact="true" v-else>No notes found</UIMenuItem>
|
||||
</div>
|
||||
</ul>
|
||||
</UIMenu>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -14,21 +14,15 @@ const emit = defineEmits<{
|
||||
const element = ref<HTMLElement | null>(null)
|
||||
</script>
|
||||
<template>
|
||||
<li class="flex w-full flex-row" ref="element">
|
||||
<a
|
||||
class="items-center px-2 py-1 w-full"
|
||||
@click.stop.prevent="() => emit('goToNote', element)"
|
||||
@mousedown.prevent
|
||||
:class="{
|
||||
disabled: activeNote?.id === result.id,
|
||||
active: props.activeResult?.id === result.id
|
||||
}"
|
||||
>
|
||||
<span class="badge-ghost badge badge-sm mr-0.5" v-if="activeNote?.id === result.id">
|
||||
current
|
||||
</span>
|
||||
<span class="flex-grow overflow-hidden whitespace-nowrap">{{ result.title }}</span>
|
||||
<span class="whitespace-nowrap">{{ formatDate(result.modified) }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<UIMenuItem
|
||||
class="flex w-full items-center"
|
||||
@click.stop.prevent="() => emit('goToNote', element)"
|
||||
@mousedown.prevent
|
||||
:disabled="activeNote?.id === result.id"
|
||||
:active="props.activeResult?.id === result.id"
|
||||
>
|
||||
<UIBadge size="sm" variant="ghost" class="mr-0.5" v-if="activeNote?.id === result.id">current</UIBadge>
|
||||
<span class="flex-grow overflow-hidden whitespace-nowrap">{{ result.title }}</span>
|
||||
<span class="whitespace-nowrap">{{ formatDate(result.modified) }}</span>
|
||||
</UIMenuItem>
|
||||
</template>
|
||||
|
||||
@@ -41,7 +41,7 @@ const authModalInitialStateOpen = ref<boolean>(authUI.isPendingRedirect())
|
||||
<UIButton
|
||||
size="sm"
|
||||
variant="outline"
|
||||
class="search-active-hide py-1 text-white"
|
||||
class="search-active-hide py-1 text-white topbar-button"
|
||||
@click="addNote('Untitled new note', '', true)"
|
||||
>
|
||||
<i class="fas fa-plus-circle text-[1.1rem]" />
|
||||
@@ -51,7 +51,7 @@ const authModalInitialStateOpen = ref<boolean>(authUI.isPendingRedirect())
|
||||
<UIButton
|
||||
size="sm"
|
||||
variant="outline"
|
||||
class="search-active-hide py-1 text-white"
|
||||
class="search-active-hide py-1 text-white topbar-button"
|
||||
@click="open"
|
||||
>
|
||||
Sign in
|
||||
@@ -79,7 +79,7 @@ const authModalInitialStateOpen = ref<boolean>(authUI.isPendingRedirect())
|
||||
#logo:hover {
|
||||
text-shadow: 0 0 5px white, 0 0 10px white, 0 0 15px white;
|
||||
}
|
||||
.btn-outline {
|
||||
.topbar-button {
|
||||
@apply hover:border-white hover:bg-white hover:text-primary focus-visible:outline-white;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ const handleClick = (fn: (...args: any[]) => any) => {
|
||||
<OnClickOutside>
|
||||
<UIDropdown class="search-active-hide">
|
||||
<template #activator>
|
||||
<UIButton :dropdown="true" size="sm" variant="outline" class="py-1 text-white">
|
||||
<UIButton :dropdown="true" size="sm" variant="outline" class="py-1 text-white topbar-button">
|
||||
<i class="fa-fw fa-solid fa-user-gear" />
|
||||
</UIButton>
|
||||
</template>
|
||||
|
||||
@@ -93,10 +93,10 @@ const deleteSelectedNotes = (closeModal: () => void) => {
|
||||
</td>
|
||||
<td>{{ note.wordCount }}</td>
|
||||
<td>
|
||||
<div class="badge" v-if="note.references.length > 0">
|
||||
<UIBadge v-if="note.references.length > 0">
|
||||
<i data-v-41bbc26f="" class="fas fa-fw fa-sign-out-alt mr-1"></i>
|
||||
{{ note.references.length }}
|
||||
</div>
|
||||
</UIBadge>
|
||||
</td>
|
||||
<td>{{ formatDate(note.modified) }}</td>
|
||||
</tr>
|
||||
|
||||
@@ -7,12 +7,12 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
})
|
||||
|
||||
const styleClass = computed(() => {
|
||||
const colorClass = `alert-${props.color}`
|
||||
const colorClass = `dui-alert-${props.color}`
|
||||
return [colorClass]
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="alert shadow-lg" :class="styleClass">
|
||||
<div class="dui-alert shadow-lg" :class="styleClass">
|
||||
<div><slot></slot></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
31
src/components/ui/UIBadge.vue
Normal file
31
src/components/ui/UIBadge.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
size: 'xs' | 'sm' | 'md' | 'lg'
|
||||
variant?: 'regular' | 'outline' | 'ghost'
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: 'md',
|
||||
variant: 'regular'
|
||||
})
|
||||
|
||||
const styleClass = computed(() => {
|
||||
const sizeVariants = {
|
||||
xs: 'dui-badge-xs',
|
||||
sm: 'dui-badge-sm',
|
||||
md: 'dui-badge-md',
|
||||
lg: 'dui-badge-lg'
|
||||
}
|
||||
const variantVariants = {
|
||||
regular: '',
|
||||
outline: 'dui-badge-outline',
|
||||
ghost: 'dui-badge-ghost'
|
||||
}
|
||||
const sizeClass = sizeVariants[props.size]
|
||||
const variantClass = variantVariants[props.variant]
|
||||
return [sizeClass, variantClass]
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div class="dui-badge" :class="styleClass"><slot></slot></div>
|
||||
</template>
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
size?: string
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg'
|
||||
variant?: 'regular' | 'outline'
|
||||
color?: string
|
||||
color?: 'regular' | 'primary'
|
||||
dropdown?: boolean
|
||||
}
|
||||
|
||||
@@ -14,18 +14,29 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
})
|
||||
|
||||
const styleClass = computed(() => {
|
||||
const colorVariants: { [key: string]: string } = {
|
||||
primary: 'btn-primary'
|
||||
const sizeVariants = {
|
||||
xs: 'dui-btn-xs',
|
||||
sm: 'dui-btn-sm',
|
||||
md: 'dui-btn-md',
|
||||
lg: 'dui-btn-lg'
|
||||
}
|
||||
const sizeClass = `btn-${props.size}`
|
||||
const variantClass = props.variant !== 'regular' ? `btn-${props.variant}` : ''
|
||||
const colorClass = props.color !== 'regular' ? colorVariants[props.color] : ''
|
||||
const colorVariants = {
|
||||
regular: '',
|
||||
primary: 'dui-btn-primary'
|
||||
}
|
||||
const variantVariants = {
|
||||
regular: '',
|
||||
outline: 'dui-btn-outline'
|
||||
}
|
||||
const sizeClass = sizeVariants[props.size]
|
||||
const variantClass = variantVariants[props.variant]
|
||||
const colorClass = colorVariants[props.color]
|
||||
return [sizeClass, variantClass, colorClass]
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<label class="btn duration-0" :class="styleClass" v-if="props.dropdown" tabindex="0">
|
||||
<label class="dui-btn duration-0" :class="styleClass" v-if="props.dropdown" tabindex="0">
|
||||
<slot></slot>
|
||||
</label>
|
||||
<button class="btn duration-0" :class="styleClass" v-else><slot></slot></button>
|
||||
<button class="dui-btn duration-0" :class="styleClass" v-else><slot></slot></button>
|
||||
</template>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<template>
|
||||
<div class="btn-group"><slot></slot></div>
|
||||
<div class="dui-btn-group"><slot></slot></div>
|
||||
</template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="dropdown-end dropdown">
|
||||
<div class="dui-dropdown-end dui-dropdown">
|
||||
<slot name="activator" tabindex="0"></slot>
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="dropdown-content menu rounded-box menu-compact mt-1 w-52 bg-base-100 p-2 text-base-content shadow"
|
||||
class="dui-dropdown-content dui-menu dui-menu-compact rounded-box mt-1 w-52 bg-base-100 p-2 text-base-content shadow"
|
||||
>
|
||||
<slot name="items"></slot>
|
||||
</ul>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<li class="text-base">
|
||||
<a><slot></slot></a>
|
||||
<a class="rounded-lg"><slot></slot></a>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
16
src/components/ui/UIMenu.vue
Normal file
16
src/components/ui/UIMenu.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
compact?: boolean
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const styleClass = computed(() => {
|
||||
const compactClass = props.compact && 'dui-menu-compact'
|
||||
return [compactClass]
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<ul tabindex="0" class="dui-menu rounded-md bg-base-100" :class="styleClass">
|
||||
<slot></slot>
|
||||
</ul>
|
||||
</template>
|
||||
28
src/components/ui/UIMenuItem.vue
Normal file
28
src/components/ui/UIMenuItem.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
title?: boolean
|
||||
disabled?: boolean
|
||||
active?: boolean
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const styleClass = computed(() => {
|
||||
const titleClass = props.title
|
||||
? 'dui-menu-item dui-menu-title !opacity-100 space-x-2 !text-xl font-bold text-secondary'
|
||||
: ''
|
||||
return [titleClass]
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<li :class="styleClass">
|
||||
<span class="flex items-center" v-if="props.title"><slot></slot></span>
|
||||
<a
|
||||
class="w-full rounded-md"
|
||||
:class="{ 'dui-disabled': props.disabled, 'dui-active': props.active }"
|
||||
v-else
|
||||
>
|
||||
<slot></slot>
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
@@ -52,13 +52,13 @@ defineExpose({ open, close })
|
||||
<slot name="activator" v-bind="slotProps"></slot>
|
||||
<Teleport to="body">
|
||||
<Transition @enter="onEnter" @leave="onLeave" appear>
|
||||
<div class="modal bg-neutral-800 bg-opacity-60" v-if="show" ref="modal">
|
||||
<div class="modal-box" ref="modalBox">
|
||||
<div class="dui-modal bg-neutral-800 bg-opacity-60" v-if="show" ref="modal">
|
||||
<div class="dui-modal-box" ref="modalBox">
|
||||
<h3 class="text-lg font-bold" v-if="$slots.title"><slot name="title" /></h3>
|
||||
<p class="py-4">
|
||||
<slot v-bind="slotProps" />
|
||||
</p>
|
||||
<div class="modal-action">
|
||||
<div class="dui-modal-action">
|
||||
<slot name="actions" v-bind="slotProps">
|
||||
<UIButton size="sm" @click="close">Close</UIButton>
|
||||
</slot>
|
||||
|
||||
@@ -5,11 +5,11 @@ interface Props {
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const styleClass = computed(() => {
|
||||
const densityClass = props.density ? 'table-compact' : ''
|
||||
const densityClass = props.density ? 'dui-table-compact' : ''
|
||||
return [densityClass]
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table class="table" :class="styleClass"><slot></slot></table>
|
||||
<table class="dui-table" :class="styleClass"><slot></slot></table>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
modelValue: any
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl'
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg'
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -13,7 +13,13 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const styleClass = computed(() => {
|
||||
const sizeClass = `input-${props.size}`
|
||||
const sizeVariants = {
|
||||
'xs': 'dui-input-xs',
|
||||
'sm': 'dui-input-sm',
|
||||
'md': 'dui-input-md',
|
||||
'lg': 'dui-input-lg'
|
||||
}
|
||||
const sizeClass = sizeVariants[props.size]
|
||||
return [sizeClass]
|
||||
})
|
||||
</script>
|
||||
@@ -22,7 +28,7 @@ const styleClass = computed(() => {
|
||||
type="text"
|
||||
:value="props.modelValue"
|
||||
@input="emit('update:modelValue', ($event.target as HTMLInputElement)?.value)"
|
||||
class="input-bordered input input-sm my-1 ml-auto mr-1 max-w-xs flex-grow"
|
||||
class="dui-input-bordered dui-input my-1 ml-auto mr-1 max-w-xs flex-grow"
|
||||
:class="styleClass"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -31,6 +31,7 @@ export default {
|
||||
},
|
||||
plugins: [require('daisyui')],
|
||||
daisyui: {
|
||||
prefix: 'dui-',
|
||||
themes: [
|
||||
{
|
||||
contexted: {
|
||||
|
||||
Reference in New Issue
Block a user