Compare commits
53 Commits
features/m
...
feat/edito
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25a9099a18 | ||
|
|
c208393f9f | ||
|
|
d75f3b5423 | ||
|
|
97ce5b3553 | ||
|
|
0a35f441e0 | ||
|
|
c8a345406c | ||
|
|
119968e7fc | ||
|
|
9b8f48ad8e | ||
|
|
2199359b96 | ||
|
|
422673cc4c | ||
|
|
6aad01c96f | ||
|
|
0c96466263 | ||
|
|
7697e818bf | ||
|
|
fd766b9f42 | ||
|
|
0e7b60235a | ||
|
|
300507bbed | ||
|
|
693f506610 | ||
|
|
f2076e413c | ||
|
|
6b02629b01 | ||
|
|
1d8b56c58e | ||
|
|
8290d02900 | ||
|
|
b67f663f05 | ||
|
|
456135d679 | ||
|
|
7fdab8601f | ||
|
|
68b9a38f83 | ||
|
|
77752e8164 | ||
|
|
1d74d6f64b | ||
|
|
b0975ee293 | ||
|
|
33f4f78ea7 | ||
|
|
4a04728183 | ||
|
|
8cd20aa386 | ||
|
|
8e325196e6 | ||
|
|
47883d1577 | ||
|
|
4433f5f1b6 | ||
|
|
f132e6d1e0 | ||
|
|
245fb421b3 | ||
|
|
46d7aa74f9 | ||
|
|
9e40ab0982 | ||
|
|
63d5ba2224 | ||
|
|
114e235a93 | ||
|
|
f03d952183 | ||
|
|
45eefbe35d | ||
|
|
18f332be54 | ||
|
|
67b79000f6 | ||
|
|
896bac5f83 | ||
|
|
09cd25ce33 | ||
|
|
1cf8510a7b | ||
|
|
a83096a17b | ||
|
|
216617a8e6 | ||
|
|
a668fa8d81 | ||
|
|
0fdb1508a4 | ||
|
|
d7447eb700 | ||
|
|
c2712f7b86 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -26,3 +26,5 @@ logs
|
||||
# Supabase
|
||||
.branches
|
||||
.temp
|
||||
|
||||
.scannerwork/
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ConfigProvider } from "radix-vue"
|
||||
import { cn } from "./lib/utils";
|
||||
|
||||
useHead({
|
||||
titleTemplate: (titleChunk) => {
|
||||
@@ -27,33 +26,17 @@ useHead({
|
||||
})
|
||||
|
||||
const useIdFunction = () => useId()
|
||||
|
||||
const { isSidebarOpened } = storeToRefs(useUiStore())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-screen">
|
||||
<NuxtLoadingIndicator />
|
||||
|
||||
<NuxtLayout>
|
||||
<ConfigProvider :use-id="useIdFunction">
|
||||
<div
|
||||
class="h-full grid md:grid-cols-[auto_1fr] dark:bg-black shadow-body-light dark:shadow-body-dark transition-colors after:absolute after:transition-colors"
|
||||
:class="cn({
|
||||
'max-md:after:bg-transparent': isSidebarOpened,
|
||||
'has-sidebar max-md:after:bg-black/20 md:after:opacity-0 md:after:pointer-events-none': isSidebarOpened
|
||||
})"
|
||||
>
|
||||
<Sidebar />
|
||||
|
||||
<div
|
||||
class="wrapper max-h-screen transition-all"
|
||||
>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
</NuxtLayout>
|
||||
</ConfigProvider>
|
||||
|
||||
<ClientOnly>
|
||||
<UiToaster />
|
||||
@@ -116,6 +116,11 @@
|
||||
--color-event-white-background: var(--event-white-background);
|
||||
}
|
||||
|
||||
::selection {
|
||||
color: var(--color-background);
|
||||
background: color-mix(in srgb, var(--color-primary), var(--color-foreground) 20%)
|
||||
}
|
||||
|
||||
.event-button,
|
||||
.event-popover,
|
||||
.event-callout,
|
||||
70
app/assets/_content.css
Normal file
70
app/assets/_content.css
Normal file
@@ -0,0 +1,70 @@
|
||||
.content {
|
||||
> * + * {
|
||||
margin-top: .5em;
|
||||
|
||||
@variant md {
|
||||
margin-top: .75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
|
||||
@variant md {
|
||||
font-size: var(--text-4xl);
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: var(--font-weight-bold);
|
||||
|
||||
@variant md {
|
||||
font-size: var(--text-2xl);
|
||||
}
|
||||
}
|
||||
h3 {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: var(--font-weight-bold);
|
||||
|
||||
@variant md {
|
||||
font-size: var(--text-xl);
|
||||
}
|
||||
}
|
||||
h4 {
|
||||
font-size: var(--text-md);
|
||||
font-weight: var(--font-weight-bold);
|
||||
|
||||
@variant md {
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Normal link */
|
||||
p a:not([class]) {
|
||||
color: var(--color-sky-600);
|
||||
text-underline-offset: .25rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-sky-500);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@variant dark {
|
||||
color: var(--color-teal-500);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-teal-300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: square;
|
||||
padding-inline-start: 1.5rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-block: 2rem;
|
||||
}
|
||||
}
|
||||
@@ -2,3 +2,9 @@
|
||||
--text-2xs: 0.7rem;
|
||||
--text-2xs--line-height: 0.75rem;
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.flow > * + * {
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
@import 'tailwindcss';
|
||||
|
||||
@config '../tailwind.config.js';
|
||||
@config '../../tailwind.config.js';
|
||||
|
||||
@import "./theme.css" layer(theme);
|
||||
@import "./_typography.css" layer(theme);
|
||||
@import "./_typography.css" layer(utilities);
|
||||
@import "./_colors.css" layer(theme);
|
||||
@import "./_colors.css" layer(utilities);
|
||||
|
||||
@import "./_content.css";
|
||||
|
||||
/*
|
||||
The default border color has changed to `currentcolor` in Tailwind CSS v4,
|
||||
so we've added these compatibility styles to make sure everything still
|
||||
@@ -31,18 +34,30 @@ body {
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
.fade-leave-active,
|
||||
.fade-group-enter-active,
|
||||
.fade-group-leave-active {
|
||||
transition: all .5s ease;
|
||||
}
|
||||
.fade-delay-enter-active,
|
||||
.fade-delay-leave-active {
|
||||
.fade-delay-leave-active,
|
||||
.fade-group-delay-enter-active,
|
||||
.fade-group-delay-leave-active {
|
||||
transition: all .5s ease 1s;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to,
|
||||
.fade-delay-enter-from,
|
||||
.fade-delay-leave-to {
|
||||
.fade-delay-leave-to,
|
||||
.fade-group-enter-from,
|
||||
.fade-group-leave-to,
|
||||
.fade-group-delay-enter-from,
|
||||
.fade-group-delay-leave-to {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.fade-group-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
--popover: hsl(0 0% 100%);
|
||||
--popover-foreground: hsl(222.2 84% 4.9%);
|
||||
--popover-border: rgb(175, 224, 200);
|
||||
|
||||
--card: hsl(0 0% 100%);
|
||||
--card-foreground: hsl(222.2 84% 4.9%);
|
||||
@@ -14,16 +15,16 @@
|
||||
--border: hsl(214.3 31.8% 91.4%);
|
||||
--input: hsl(214.3 31.8% 91.4%);
|
||||
|
||||
--primary: hsl(245 58% 51%);
|
||||
--primary-foreground: hsl(0 0% 100%);
|
||||
--primary: rgb(101, 230, 166);
|
||||
--primary-foreground: hsl(222.2 84% 4.9%);
|
||||
|
||||
--secondary: hsl(210 50% 95%);
|
||||
--secondary-foreground: hsl(222.2 47.4% 11.2%);
|
||||
--secondary-foreground: hsl(222.2 84% 4.9%);
|
||||
|
||||
--accent: hsl(210 40% 96.1%);
|
||||
--accent-foreground: hsl(222.2 47.4% 11.2%);
|
||||
--accent: hsl(11, 100%, 86%);
|
||||
--accent-foreground: hsl(222.2 84% 4.9%);
|
||||
|
||||
--destructive: hsl(0 84.2% 60.2%);
|
||||
--destructive: hsl(0, 100%, 63%);
|
||||
--destructive-foreground: hsl(210 40% 98%);
|
||||
|
||||
--success: hsl(156 72% 67%);
|
||||
@@ -42,25 +43,26 @@
|
||||
--muted: hsl(0, 0%, 12%);
|
||||
--muted-foreground: hsl(215 20.2% 65.1%);
|
||||
|
||||
--popover: hsl(180 0 4.9%);
|
||||
--popover: hsl(165, 47%, 5%);
|
||||
--popover-foreground: hsl(210 40% 98%);
|
||||
--popover-border: hsl(165, 47%, 20%);
|
||||
|
||||
--card: hsl(180 0 4.9%);
|
||||
--card-foreground: hsl(210 40% 98%);
|
||||
|
||||
--border: hsl(0, 0%, 16%);
|
||||
--input: hsl(244 47% 20%);
|
||||
--border: hsl(0, 0%, 22.5%);
|
||||
--input: hsl(165, 47%, 20%);
|
||||
|
||||
--primary: hsl(245 58% 51%);
|
||||
--primary-foreground: hsl(0 0% 100%);
|
||||
--primary: rgb(101, 230, 166);
|
||||
--primary-foreground: hsl(180 0 4.9%);
|
||||
|
||||
--secondary: hsl(244 47% 20%);
|
||||
--secondary: hsl(222.2 47.4% 11.2%);
|
||||
--secondary-foreground: hsl(210 40% 98%);
|
||||
|
||||
--accent: hsl(244 47% 20%);
|
||||
--accent-foreground: hsl(210 40% 98%);
|
||||
--accent: hsl(11, 87%, 69%);
|
||||
--accent-foreground: hsl(222.2 84% 4.9%);
|
||||
|
||||
--destructive: hsl(0 62.8% 30.6%);
|
||||
--destructive: hsl(0, 62%, 49%);
|
||||
--destructive-foreground: hsl(210 40% 98%);
|
||||
|
||||
--success: hsl(142 72% 29%);
|
||||
@@ -81,6 +83,7 @@
|
||||
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover-border: var(--popover-border);
|
||||
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { useCalendar } from "~/stores/CalendarStore"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
import { computed, type Component, type ComputedRef } from "vue"
|
||||
|
||||
// import { PhMagnifyingGlass } from '@phosphor-icons/vue'
|
||||
@@ -6,14 +6,13 @@ const { isReadOnly } = storeToRefs(useCalendar())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<UiTooltipProvider :delay-duration="250">
|
||||
<UiTooltip>
|
||||
<UiTooltipTrigger as-child>
|
||||
<ClientOnly>
|
||||
<UiButton v-if="!isReadOnly" variant="secondary" size="icon" @click="toggleCategoriesModal(true)">
|
||||
<PhTag size="20" weight="light" />
|
||||
</UiButton>
|
||||
</ClientOnly>
|
||||
</UiTooltipTrigger>
|
||||
<UiTooltipContent>
|
||||
<p>
|
||||
@@ -22,4 +21,5 @@ const { isReadOnly } = storeToRefs(useCalendar())
|
||||
</UiTooltipContent>
|
||||
</UiTooltip>
|
||||
</UiTooltipProvider>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { breakpointsTailwind } from "@vueuse/core"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { useCalendar } from "~/stores/CalendarStore"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
import { PhCalendarBlank, PhCheckCircle, PhDotsThreeVertical, PhGear, PhTag } from "@phosphor-icons/vue"
|
||||
|
||||
const breakpoints = useBreakpoints(
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { PhArchive, PhCalendarDots, PhFile, PhFileDashed, PhFilePlus, PhPencil, PhPencilSimpleLine, PhTrash } from "@phosphor-icons/vue"
|
||||
import { DateTime } from "luxon"
|
||||
import type { Calendar } from "~/models/CalendarConfig"
|
||||
import type { Calendar } from "@@/models/CalendarConfig"
|
||||
|
||||
const props = defineProps<{
|
||||
calendar: Calendar
|
||||
@@ -64,8 +64,8 @@ const hasActions = computed(() => isOwner.value && props.showActions)
|
||||
<UiCardContent class="grow">
|
||||
<p class="flex items-center gap-1">
|
||||
<PhCalendarDots size="24" weight="fill" />
|
||||
<span v-if="calendar.eventNb?.[0].count! > 1">{{ $t("entity.calendar.hasXEvents", { count: calendar.eventNb?.[0].count }) }}</span>
|
||||
<span v-else>{{ $t("entity.calendar.hasXEvent", { count: calendar.eventNb?.[0].count }) }}</span>
|
||||
<span v-if="calendar.eventNb?.[0]!.count! > 1">{{ $t("entity.calendar.hasXEvents", { count: calendar.eventNb?.[0]!.count }) }}</span>
|
||||
<span v-else>{{ $t("entity.calendar.hasXEvent", { count: calendar.eventNb?.[0]!.count }) }}</span>
|
||||
</p>
|
||||
|
||||
<div
|
||||
@@ -1,3 +1,3 @@
|
||||
export const searchUnifier = new RegExp(/[^a-zA-Z0-9\-'']/g)
|
||||
export const searchUnifier = new RegExp(/[^a-zA-Z0-9\-']/g)
|
||||
|
||||
export type SearchMode = "characters" | "events" | undefined
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { Category } from "~/models/Category";
|
||||
import type { Category } from "@@/models/Category";
|
||||
|
||||
defineProps<{
|
||||
categories: Category[]
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { Category } from "~/models/Category";
|
||||
import type { Category } from "@@/models/Category";
|
||||
|
||||
defineProps<{
|
||||
category: Category
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { Category } from "~/models/Category";
|
||||
import type { Category } from "@@/models/Category";
|
||||
import { ScrollAreaRoot, ScrollAreaViewport, ScrollAreaScrollbar, ScrollAreaThumb } from "radix-vue"
|
||||
|
||||
const { categories } = defineProps<{
|
||||
@@ -51,7 +51,7 @@ function closeDeleteDialog() {
|
||||
<UiDialogContent
|
||||
:disable-outside-pointer-events="true"
|
||||
:trap-focus="true"
|
||||
class="min-w-96 border-indigo-200 dark:bg-slate-950 dark:border-indigo-950"
|
||||
class="min-w-96"
|
||||
@escape-key-down="closeDeleteDialog"
|
||||
@focus-outside="closeDeleteDialog"
|
||||
@interact-outside="closeDeleteDialog"
|
||||
@@ -2,7 +2,7 @@
|
||||
import { PhPlus } from "@phosphor-icons/vue"
|
||||
import { useToast } from "~/components/ui/toast"
|
||||
import { ToastLifetime } from "~/components/ui/toast/use-toast"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const { toast } = useToast()
|
||||
const { t } = useI18n()
|
||||
@@ -86,7 +86,7 @@ async function submitNew() {
|
||||
<div class="border-y-[1px] border-b-foreground/10 mr-4">
|
||||
<form
|
||||
ref="rowRef"
|
||||
class="grid grid-cols-12 items-center gap-4 p-1 bg-transparent hover:bg-slate-50 dark:bg-transparent dark:hover:bg-slate-900"
|
||||
class="grid grid-cols-12 items-center gap-4 p-1 bg-primary/0 hover:bg-primary/15"
|
||||
@submit.prevent="submitNew"
|
||||
>
|
||||
<div v-if="currentMode === 'add'" class="col-span-1" />
|
||||
@@ -2,8 +2,8 @@
|
||||
import { PhCheck, PhTrash } from "@phosphor-icons/vue"
|
||||
import { useToast } from "~/components/ui/toast"
|
||||
import { ToastLifetime } from "~/components/ui/toast/use-toast"
|
||||
import { cn } from "~/lib/utils"
|
||||
import type { Category } from "~/models/Category"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { Category } from "@@/models/Category"
|
||||
|
||||
const { toast } = useToast()
|
||||
const { t } = useI18n()
|
||||
@@ -13,7 +13,7 @@ const { category } = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "on-delete-category", payload: Category): void
|
||||
"on-delete-category": [payload: Category]
|
||||
}>()
|
||||
|
||||
type RowMode = "edit" | "view"
|
||||
@@ -103,8 +103,8 @@ function handleQueryDelete() {
|
||||
<form
|
||||
class="grid grid-cols-12 items-center gap-4 p-1 border-b-[1px] border-b-foreground/10"
|
||||
:class="cn(
|
||||
{ 'bg-slate-100 hover:bg-slate-200 dark:bg-slate-900 dark:hover:bg-slate-800': currentMode === 'edit' },
|
||||
{ 'bg-transparent hover:bg-slate-50 dark:bg-transparent dark:hover:bg-slate-900': currentMode !== 'edit' }
|
||||
{ 'bg-primary/10 hover:bg-primary/20': currentMode === 'edit' },
|
||||
{ 'bg-primary/0 hover:bg-primary/15': currentMode !== 'edit' }
|
||||
)"
|
||||
@submit.prevent="submitUpdate"
|
||||
>
|
||||
@@ -162,9 +162,9 @@ function handleQueryDelete() {
|
||||
v-if="currentMode === 'edit' && categorySkeleton"
|
||||
>
|
||||
<UiButton
|
||||
variant="secondary"
|
||||
variant="default"
|
||||
size="icon"
|
||||
class="w-6 h-6 rounded-full bg-emerald-500 hover:bg-emerald-600 text-white"
|
||||
class="w-6 h-6 rounded-full"
|
||||
:title="$t('ui.actions.edit')"
|
||||
@click="submitUpdate"
|
||||
>
|
||||
@@ -173,9 +173,9 @@ function handleQueryDelete() {
|
||||
</li>
|
||||
<li v-else-if="rowHovered">
|
||||
<UiButton
|
||||
variant="secondary"
|
||||
variant="destructive"
|
||||
size="icon"
|
||||
class="w-6 h-6 rounded-full hover:bg-red-600 hover:text-white"
|
||||
class="w-6 h-6 rounded-full"
|
||||
:title="$t('ui.actions.delete')"
|
||||
@click="handleQueryDelete"
|
||||
>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { PhX } from "@phosphor-icons/vue";
|
||||
import type { World } from "~/models/World";
|
||||
import type { World } from "@@/models/World";
|
||||
|
||||
defineProps<{
|
||||
world: World,
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { RPGDate } from "~/models/Date";
|
||||
import type { RPGDate } from "@@/models/Date";
|
||||
|
||||
const { eventSkeleton, operationInProgress, currentRPGDate } = storeToRefs(useCalendar())
|
||||
const { resetSkeleton } = useCalendar()
|
||||
@@ -59,7 +59,7 @@ watch(currentRPGDate, () => {
|
||||
:collision-padding="60"
|
||||
:disable-outside-pointer-events="true"
|
||||
:trap-focus="true"
|
||||
class="pl-3 w-[30rem] max-w-full border-indigo-200 dark:bg-slate-950 dark:border-indigo-950"
|
||||
class="pl-3 w-[30rem] max-w-full"
|
||||
@escape-key-down.prevent="handleClosing"
|
||||
@pointer-down-outside.prevent="handleClosing"
|
||||
>
|
||||
@@ -2,7 +2,7 @@
|
||||
import { PhCircleNotch } from "@phosphor-icons/vue";
|
||||
import { useToast } from "~/components/ui/toast";
|
||||
import { ToastLifetime } from "~/components/ui/toast/use-toast";
|
||||
import type { Calendar } from "~/models/CalendarConfig";
|
||||
import type { Calendar } from "@@/models/CalendarConfig";
|
||||
|
||||
const { toast } = useToast()
|
||||
const { t } = useI18n()
|
||||
@@ -76,14 +76,6 @@ function handleClosing() {
|
||||
</UiAlertDialogDescription>
|
||||
|
||||
<form @submit.prevent="handleAction">
|
||||
<div class="grid grid-cols-2 gap-y-4">
|
||||
<div class="text-red-500 ml-8">
|
||||
<span class="text-sm">
|
||||
<!-- {{ formErrors.message }} -->
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="flex gap-2 justify-between">
|
||||
<UiButton type="button" size="sm" variant="outline" @click="handleClosing">
|
||||
{{ $t('ui.action.back') }}
|
||||
@@ -27,7 +27,7 @@ function handleClosing(e: Event): void {
|
||||
<UiAlertDialogContent
|
||||
:disable-outside-pointer-events="true"
|
||||
:trap-focus="true"
|
||||
class="min-w-96 border-indigo-200 dark:bg-slate-950 dark:border-indigo-950"
|
||||
class="min-w-96"
|
||||
@escape-key-down="handleClosing"
|
||||
@focus-outside="handleClosing"
|
||||
@interact-outside="handleClosing"
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { PhX } from "@phosphor-icons/vue";
|
||||
import type { Calendar } from "~/models/CalendarConfig";
|
||||
import type { World } from "~/models/World";
|
||||
import type { Calendar } from "@@/models/CalendarConfig";
|
||||
import type { World } from "@@/models/World";
|
||||
|
||||
const props = defineProps<{
|
||||
calendar: Calendar | null,
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { cn } from "~/lib/utils"
|
||||
import type { RPGDate } from "~/models/Date"
|
||||
import type { CalendarEvent } from "~/models/CalendarEvent"
|
||||
import { useCalendar } from "~/stores/CalendarStore"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { RPGDate } from "@@/models/Date"
|
||||
import type { CalendarEvent } from "@@/models/CalendarEvent"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core"
|
||||
|
||||
import {
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
PhDotsThreeOutlineVertical,
|
||||
PhEye
|
||||
} from "@phosphor-icons/vue"
|
||||
import type { CollisionPadding } from "~/models/Popover"
|
||||
import type { CollisionPadding } from "@@/models/Popover"
|
||||
|
||||
const { defaultDate, getFormattedDateTitle, jumpToDate, getRelativeString, revealEditEventModal, revealDeleteEventModal } = useCalendar()
|
||||
const { lastActiveEvent, isReadOnly } = storeToRefs(useCalendar())
|
||||
@@ -160,8 +160,8 @@ function deployDeleteModal() {
|
||||
<template v-if="event.description">
|
||||
<hr class="border-border mt-2" >
|
||||
|
||||
<div class="max-h-48 overflow-y-auto mt-2 text-sm text-slate-600 dark:text-slate-300">
|
||||
{{ event.description }}
|
||||
<div class="max-h-48 overflow-y-auto mt-2 text-sm opacity-80">
|
||||
<div class="content-editor" v-html="event.description" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -187,19 +187,19 @@ function deployDeleteModal() {
|
||||
</menu>
|
||||
|
||||
<nav v-if="event.startDate && event.endDate" class="mt-2 flex gap-2">
|
||||
<UiBadge class="hover:bg-indigo-400 dark:hover:bg-slate-300" as-child>
|
||||
<UiBadge as-child>
|
||||
<button
|
||||
class="flex gap-1"
|
||||
title="Naviguer au début"
|
||||
class="flex gap-1 cursor-pointer"
|
||||
:title="$t('entity.calendar.event.gotoStart')"
|
||||
@click="handleJumpToDate(event.startDate!)"
|
||||
>
|
||||
<PhHourglassHigh size="16" weight="fill" /> {{ $t('entity.calendar.event.isStart') }}
|
||||
</button>
|
||||
</UiBadge>
|
||||
<UiBadge class="hover:bg-indigo-400 dark:hover:bg-slate-300" as-child title="Naviguer à la fin">
|
||||
<UiBadge as-child>
|
||||
<button
|
||||
class="flex gap-1"
|
||||
title="Naviguer à la fin"
|
||||
class="flex gap-1 cursor-pointer"
|
||||
:title="$t('entity.calendar.event.gotoEnd')"
|
||||
@click="handleJumpToDate(event.endDate!)"
|
||||
>
|
||||
<PhHourglassLow size="16" weight="fill" /> {{ $t('entity.calendar.event.isEnd') }}
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { cn } from "~/lib/utils"
|
||||
import type { RPGDate } from "~/models/Date"
|
||||
import type { CalendarEvent } from "~/models/CalendarEvent"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { RPGDate } from "@@/models/Date"
|
||||
import type { CalendarEvent } from "@@/models/CalendarEvent"
|
||||
|
||||
const props = defineProps<{
|
||||
event: CalendarEvent
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Calendar } from "~/models/CalendarConfig";
|
||||
import type { Calendar } from "@@/models/CalendarConfig";
|
||||
import { PhAlarm, PhCalendarDots, PhCircleNotch, PhWrench } from "@phosphor-icons/vue";
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -57,13 +57,11 @@ async function handleSubmit() {
|
||||
}
|
||||
|
||||
/**
|
||||
* === Watch for name changes to display above ===
|
||||
* Watch for name changes to display above
|
||||
*/
|
||||
const emit = defineEmits<{
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
(e: "on-changed-name", calendarName: string): void
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
(e: "on-close"): void
|
||||
"on-changed-name": [calendarName: string]
|
||||
"on-close": []
|
||||
}>()
|
||||
|
||||
/** Hook to emit a debounced event for the changed skeleton name */
|
||||
@@ -111,7 +109,7 @@ function handleFormCancel() {
|
||||
name="new-calendar-name"
|
||||
required
|
||||
:placeholder="$t('common.title')"
|
||||
class="w-full py-2 -mx-1 px-1 text-xl border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-blue-600"
|
||||
class="w-full py-2 -mx-1 px-1 text-xl border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-primary invalid:border-destructive"
|
||||
@input="handleNameChange"
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { RPGDate } from "~/models/Date";
|
||||
import type { RPGDate } from "@@/models/Date";
|
||||
import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhTag } from "@phosphor-icons/vue"
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -66,7 +66,7 @@ function handleCancel() {
|
||||
:placeholder="$t('entity.calendar.event.title')"
|
||||
:maxlength="120"
|
||||
pattern="([A-Za-zÀ-ÖØ-öø-ÿ0-9\s\&\-\~]+){3,120}"
|
||||
class="w-full -my-1 py-1 -mx-1 px-1 text-lg border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-blue-600 invalid:border-red-500"
|
||||
class="w-full -my-1 py-1 -mx-1 px-1 text-lg border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-primary invalid:border-destructive"
|
||||
>
|
||||
<div class="mt-2 mb-1 text-xs opacity-50">
|
||||
{{ t('entity.calendar.event.patterns.title') }}
|
||||
@@ -74,14 +74,11 @@ function handleCancel() {
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 my-2 pl-8">
|
||||
<textarea
|
||||
id="new-event-description"
|
||||
<InputEditor
|
||||
disable-blocks
|
||||
v-model="eventSkeleton.description"
|
||||
name="new-event-description"
|
||||
:placeholder="$t('entity.addDescription')"
|
||||
:maxlength="1200"
|
||||
class="w-full -my-1 py-1 -mx-1 px-1 min-h-24 max-h-36 text-sm border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-blue-600 invalid:border-red-500"
|
||||
/>
|
||||
|
||||
<div class="mt-2 mb-1 text-xs opacity-50">
|
||||
{{ t('entity.calendar.event.patterns.description') }}
|
||||
</div>
|
||||
@@ -119,14 +116,6 @@ function handleCancel() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="col-span-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhTag size="18" weight="fill" />
|
||||
|
||||
<CalendarInputEventCategories v-model="eventSkeleton.secondaryCategories" :placeholder="$t('entity.category.addSecondaries')" />
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="col-span-2 mb-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhMapPinArea size="18" weight="fill" />
|
||||
@@ -140,7 +129,7 @@ function handleCancel() {
|
||||
:placeholder="$t('entity.calendar.event.addLocation')"
|
||||
:maxlength="160"
|
||||
pattern="([A-Za-zÀ-ÖØ-öø-ÿ0-9\s\&\-\~]+){3,160}"
|
||||
class="w-full -my-1 py-2 px-2 text-sm border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-blue-600"
|
||||
class="w-full -my-1 py-2 px-2 text-sm border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-primary invalid:border-destructive"
|
||||
>
|
||||
<div class="mt-2 mb-1 text-xs opacity-50">
|
||||
{{ t('entity.calendar.event.patterns.location') }}
|
||||
@@ -155,14 +144,9 @@ function handleCancel() {
|
||||
<PhEyeClosed v-else size="18" />
|
||||
|
||||
<div class="flex items-center gap-x-2">
|
||||
<UiSwitch id="new-event-visibility" v-model:checked="eventSkeleton.hidden" />
|
||||
<UiCheckbox id="new-event-visibility" v-model:checked="eventSkeleton.hidden" />
|
||||
<UiLabel for="new-event-visibility">
|
||||
<template v-if="!eventSkeleton.hidden">
|
||||
{{ $t('entity.calendar.event.isPublic') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('entity.calendar.event.isHidden') }}
|
||||
</template>
|
||||
{{ $t('entity.calendar.event.hiddenLabel') }}
|
||||
</UiLabel>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Calendar } from "~/models/CalendarConfig";
|
||||
import type { Calendar } from "@@/models/CalendarConfig";
|
||||
import { PhCircleNotch, PhWrench } from "@phosphor-icons/vue";
|
||||
import type { World } from "~/models/World";
|
||||
import type { World } from "@@/models/World";
|
||||
|
||||
const props = defineProps<{
|
||||
calendar: Calendar | null,
|
||||
@@ -53,13 +53,11 @@ async function handleSubmit() {
|
||||
}
|
||||
|
||||
/**
|
||||
* === Watch for name changes to display above ===
|
||||
* Watch for name changes to display above
|
||||
*/
|
||||
const emit = defineEmits<{
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
(e: "on-changed-name", calendarName: string): void
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
(e: "on-close"): void
|
||||
"on-changed-name": [calendarName: string]
|
||||
"on-close": []
|
||||
}>()
|
||||
|
||||
/** Hook to emit a debounced event for the changed skeleton name */
|
||||
@@ -84,20 +82,6 @@ function handleFormCancel() {
|
||||
{{ $t('entity.calendar.actionDialog.tabs.general.title') }}
|
||||
</div>
|
||||
</UiTabsTrigger>
|
||||
<!-- <UiTabsTrigger value="months" class="font-bold">
|
||||
<div class="flex items-center gap-1">
|
||||
<PhCalendarDots size="18" weight="fill" />
|
||||
|
||||
{{ $t('entity.calendar.actionDialog.tabs.months.title') }}
|
||||
</div>
|
||||
</UiTabsTrigger>
|
||||
<UiTabsTrigger value="today" class="font-bold">
|
||||
<div class="flex items-center gap-1">
|
||||
<PhAlarm size="18" weight="fill" />
|
||||
|
||||
{{ $t('entity.calendar.actionDialog.tabs.today.title') }}
|
||||
</div>
|
||||
</UiTabsTrigger> -->
|
||||
</UiTabsList>
|
||||
<UiTabsContent value="global" class="grid gap-4">
|
||||
<input
|
||||
@@ -107,7 +91,7 @@ function handleFormCancel() {
|
||||
name="new-calendar-name"
|
||||
required
|
||||
:placeholder="$t('common.title')"
|
||||
class="w-full py-2 -mx-1 px-1 text-xl border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-blue-600"
|
||||
class="w-full py-2 -mx-1 px-1 text-xl border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-primary invalid:border-destructive"
|
||||
@input="handleNameChange"
|
||||
>
|
||||
|
||||
@@ -127,12 +111,6 @@ function handleFormCancel() {
|
||||
<InputColor id="new-calendar-color" v-model="calendarSkeleton.color" />
|
||||
</div>
|
||||
</UiTabsContent>
|
||||
<!-- <UiTabsContent value="months">
|
||||
<CalendarInputMonthList v-model:model-value="calendarSkeleton.months" />
|
||||
</UiTabsContent>
|
||||
<UiTabsContent value="today">
|
||||
<CalendarInputTodaySelect v-model:model-value="calendarSkeleton.today" :available-months="calendarSkeleton.months"/>
|
||||
</UiTabsContent> -->
|
||||
</UiTabs>
|
||||
|
||||
<footer class="flex justify-end gap-2 mt-6">
|
||||
@@ -2,7 +2,7 @@
|
||||
import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhPencilSimpleLine, PhTag } from "@phosphor-icons/vue"
|
||||
import { useToast } from "~/components/ui/toast";
|
||||
import { ToastLifetime } from "~/components/ui/toast/use-toast";
|
||||
import type { APIError } from "~/models/Errors";
|
||||
import type { APIError } from "@@/models/Errors";
|
||||
|
||||
const emit = defineEmits(["event-updated"])
|
||||
|
||||
@@ -82,7 +82,7 @@ function handleCancel() {
|
||||
:placeholder="$t('entity.calendar.event.title')"
|
||||
:minlength="3"
|
||||
:maxlength="120"
|
||||
class="w-full -my-1 py-1 -mx-1 px-1 text-lg border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-blue-600 invalid:border-red-500"
|
||||
class="w-full -my-1 py-1 -mx-1 px-1 text-lg border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-primary invalid:border-destructive"
|
||||
>
|
||||
<div class="mt-2 mb-1 text-xs opacity-50">
|
||||
{{ t('entity.calendar.event.patterns.title') }}
|
||||
@@ -92,14 +92,11 @@ function handleCancel() {
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 my-2 ml-8">
|
||||
<textarea
|
||||
id="new-event-description"
|
||||
<InputEditor
|
||||
disable-blocks
|
||||
v-model="eventSkeleton.description"
|
||||
name="new-event-description"
|
||||
:placeholder="$t('entity.addDescription')"
|
||||
:maxlength="1200"
|
||||
class="w-full -my-1 py-1 -mx-1 px-1 min-h-24 max-h-36 text-sm border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-blue-600 invalid:border-red-500"
|
||||
/>
|
||||
|
||||
<div class="mt-2 mb-1 text-xs opacity-50">
|
||||
{{ t('entity.calendar.event.patterns.description') }}
|
||||
</div>
|
||||
@@ -139,16 +136,6 @@ function handleCancel() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="col-span-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhTag size="18" weight="fill" />
|
||||
|
||||
<div class="w-1/2">
|
||||
<CalendarInputEventCategories v-model="eventSkeleton.secondaryCategories" placeholder="Ajouter des catégories secondaires" />
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="col-span-2 mb-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<PhMapPinArea size="18" weight="fill" />
|
||||
@@ -162,7 +149,7 @@ function handleCancel() {
|
||||
:placeholder="$t('entity.calendar.event.addLocation')"
|
||||
:minlength="3"
|
||||
:maxlength="160"
|
||||
class="w-full -my-1 py-2 px-2 text-sm border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-blue-600 invalid:border-red-500"
|
||||
class="w-full -my-1 py-2 px-2 text-sm border-b-[1px] bg-transparent focus-visible:outline-hidden focus-visible:border-primary invalid:border-destructive"
|
||||
>
|
||||
|
||||
<div class="mt-2 mb-1 text-xs opacity-50">
|
||||
@@ -178,14 +165,9 @@ function handleCancel() {
|
||||
<PhEyeClosed v-else size="18" />
|
||||
|
||||
<div class="flex items-center gap-x-2">
|
||||
<UiSwitch id="new-event-visibility" v-model:checked="eventSkeleton.hidden" />
|
||||
<UiCheckbox id="new-event-visibility" v-model:checked="eventSkeleton.hidden" />
|
||||
<UiLabel for="new-event-visibility">
|
||||
<template v-if="!eventSkeleton.hidden">
|
||||
{{ $t('entity.calendar.event.isPublic') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $t('entity.calendar.event.isHidden') }}
|
||||
</template>
|
||||
{{ $t('entity.calendar.event.hiddenLabel') }}
|
||||
</UiLabel>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Category } from "~/models/Category";
|
||||
import type { Category } from "@@/models/Category";
|
||||
|
||||
import { PhCaretDown, PhCheck } from "@phosphor-icons/vue";
|
||||
|
||||
@@ -35,7 +35,9 @@ const filteredCategories = computed(() =>
|
||||
<UiButton
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
class="relative w-full max-w-full h-fit justify-between"
|
||||
:aria-expanded="isPopoverOpen"
|
||||
aria-controls="event-categories"
|
||||
class="relative w-full max-w-full h-fit justify-between hover:bg-secondary hover:text-primary-foreground"
|
||||
>
|
||||
<template v-if="!model.length">
|
||||
{{ props.placeholder }}
|
||||
@@ -54,12 +56,13 @@ const filteredCategories = computed(() =>
|
||||
</UiButton>
|
||||
</UiPopoverTrigger>
|
||||
<UiPopoverContent
|
||||
align="start"
|
||||
id="event-categories"
|
||||
:align="'start'"
|
||||
side="bottom"
|
||||
:collision-padding="50"
|
||||
class="w-fit h-[33vh] p-0"
|
||||
>
|
||||
<UiCommand v-model="modelBuffer" v-model:searchTerm="searchTerm" :multiple="true">
|
||||
<UiCommand v-model="modelBuffer" v-model:search-term="searchTerm" :multiple="true">
|
||||
<UiCommandInput :placeholder="$t('entity.category.search')" />
|
||||
<UiCommandEmpty>{{ $t('entity.category.notFoundAny') }}</UiCommandEmpty>
|
||||
<UiCommandList>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { PhCaretDown } from "@phosphor-icons/vue";
|
||||
import { cn } from "~/lib/utils";
|
||||
import type { Category } from "~/models/Category";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { Category } from "@@/models/Category";
|
||||
|
||||
const isPopoverOpen = ref<boolean>(false)
|
||||
|
||||
@@ -34,7 +34,9 @@ const filteredCategories = computed(() =>
|
||||
<UiButton
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
class="w-full max-w-full justify-between"
|
||||
:aria-expanded="isPopoverOpen"
|
||||
aria-controls="event-category"
|
||||
class="w-full max-w-full justify-between hover:bg-secondary hover:text-primary-foreground"
|
||||
>
|
||||
<template v-if="!model">
|
||||
{{ props.placeholder }}
|
||||
@@ -52,6 +54,7 @@ const filteredCategories = computed(() =>
|
||||
</UiButton>
|
||||
</UiPopoverTrigger>
|
||||
<UiPopoverContent
|
||||
id="event-category"
|
||||
align="start"
|
||||
side="bottom"
|
||||
:collision-padding="50"
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { useSortable } from "@vueuse/integrations/useSortable";
|
||||
import type { CalendarMonth } from "~/models/CalendarMonth";
|
||||
import type { CalendarMonth } from "@@/models/CalendarMonth";
|
||||
|
||||
import { PhList, PhPlus, PhTrash } from "@phosphor-icons/vue";
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import type { RPGDate } from "~/models/Date";
|
||||
import type { RPGDate } from "@@/models/Date";
|
||||
|
||||
import {
|
||||
PhXCircle
|
||||
} from "@phosphor-icons/vue"
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
const model = defineModel<RPGDate | null>()
|
||||
|
||||
@@ -117,7 +118,6 @@ function handleValueReset() {
|
||||
v-if="model"
|
||||
align="start"
|
||||
side="bottom"
|
||||
class="border-indigo-200 dark:bg-slate-950 dark:border-indigo-950"
|
||||
>
|
||||
<div class="grid grid-cols-2 items-center gap-x-2 gap-y-3">
|
||||
<UiSelect @update:model-value="handleMonthChange">
|
||||
@@ -135,16 +135,7 @@ function handleValueReset() {
|
||||
|
||||
<UiInput v-model="model.year" type="number" />
|
||||
|
||||
<!-- <nav class="flex items-center justify-end gap-2">
|
||||
<UiButton variant="outline" size="icon" class="w-8 h-8" @click="decrementModelMonth()">
|
||||
<PhCaretLeft size="14" />
|
||||
</UiButton>
|
||||
<UiButton variant="outline" size="icon" class="w-8 h-8" @click="incrementModelMonth()">
|
||||
<PhCaretRight size="14" />
|
||||
</UiButton>
|
||||
</nav> -->
|
||||
|
||||
<hr class="col-span-2" >
|
||||
<hr class="col-span-2" />
|
||||
|
||||
<div class="col-span-2">
|
||||
<div v-if="monthData" class="grid grid-cols-7 gap-1">
|
||||
@@ -152,10 +143,10 @@ function handleValueReset() {
|
||||
v-for="day in monthData.days"
|
||||
:key="`popover-day-grid-${id}-${day}`"
|
||||
class="aspect-square rounded-full text-[.8em] transition-colors"
|
||||
:class="{
|
||||
'hover:bg-indigo-200 dark:hover:bg-indigo-700': day !== model.day,
|
||||
'bg-indigo-500 hover:bg-indigo-700 text-white': day === model.day
|
||||
}"
|
||||
:class="cn({
|
||||
'hover:bg-accent hover:text-accent-foreground': day !== model.day,
|
||||
'bg-primary text-primary-foreground hover:bg-accent hover:text-accent-foreground': day === model.day
|
||||
})"
|
||||
@click="setModelDay(day)"
|
||||
>
|
||||
{{ day }}
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { CalendarMonth } from "~/models/CalendarMonth";
|
||||
import type { RPGDate } from "~/models/Date";
|
||||
import type { CalendarMonth } from "@@/models/CalendarMonth";
|
||||
import type { RPGDate } from "@@/models/Date";
|
||||
|
||||
import { PhCalendarBlank } from "@phosphor-icons/vue";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { useCalendar } from "~/stores/CalendarStore"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
import { breakpointsTailwind } from "@vueuse/core"
|
||||
|
||||
const breakpoints = useBreakpoints(
|
||||
@@ -139,7 +139,7 @@ function toFutureFar(): void {
|
||||
|
||||
<template>
|
||||
<div class="flex gap-2">
|
||||
<div class="grid items-center w-40 px-3 md:px-4 py-2 bg-white dark:bg-black border-border border-x-[1px] border-t-[1px] rounded-t-sm text-sm max-md:text-xs transition-colors">
|
||||
<div class="grid items-center w-40 px-3 md:px-4 py-2 bg-background border-border border-x-[1px] border-t-[1px] rounded-t-sm text-sm max-md:text-xs transition-colors">
|
||||
<ClientOnly>
|
||||
<span>{{ currentDate.currentDateTitle }}</span>
|
||||
|
||||
@@ -16,10 +16,10 @@ const breakpoints = useBreakpoints(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<UiTooltipProvider :delay-duration="250">
|
||||
<UiTooltip>
|
||||
<UiTooltipTrigger as-child>
|
||||
<ClientOnly>
|
||||
<UiButton
|
||||
:size="breakpoints.md.value ? 'default' : 'icon'"
|
||||
variant="secondary"
|
||||
@@ -31,11 +31,11 @@ const breakpoints = useBreakpoints(
|
||||
{{ $t('entity.calendar.date.today') }}
|
||||
</span>
|
||||
</UiButton>
|
||||
</ClientOnly>
|
||||
</UiTooltipTrigger>
|
||||
<UiTooltipContent>
|
||||
<p>{{ defaultDateFormatted }}</p>
|
||||
</UiTooltipContent>
|
||||
</UiTooltip>
|
||||
</UiTooltipProvider>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
@@ -2,12 +2,12 @@
|
||||
import {
|
||||
isCharacter,
|
||||
type Character,
|
||||
} from "~/models/Characters"
|
||||
import type { RPGDateOrder } from "~/models/Date"
|
||||
} from "@@/models/Characters"
|
||||
import type { RPGDateOrder } from "@@/models/Date"
|
||||
import {
|
||||
isCalendarEvent,
|
||||
type CalendarEvent,
|
||||
} from "~/models/CalendarEvent"
|
||||
} from "@@/models/CalendarEvent"
|
||||
import { capitalize } from "~/utils/Strings"
|
||||
import { useMagicKeys, useScroll, useStorage, whenever } from "@vueuse/core"
|
||||
import { computed, ref, watch } from "vue"
|
||||
@@ -24,8 +24,8 @@ import {
|
||||
} from "radix-vue"
|
||||
|
||||
import SearchList from "./lists/SearchList.vue"
|
||||
import type { Category } from "~/models/Category"
|
||||
import { cn } from "~/lib/utils"
|
||||
import type { Category } from "@@/models/Category"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const { isAdvancedSearchOpen, allEvents, categories } = storeToRefs(useCalendar())
|
||||
const { characters } = storeToRefs(useCharacters())
|
||||
@@ -88,7 +88,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
|
||||
results = dataToFilter.filter((item) => {
|
||||
// Filter calendar events
|
||||
if (isCalendarEvent(item)) {
|
||||
const queryString = new String(searchQuery.value)
|
||||
const queryString = (searchQuery.value as string)
|
||||
.replace(searchUnifier, "")
|
||||
.toLocaleLowerCase()
|
||||
|
||||
@@ -126,7 +126,7 @@ const searchResults = computed<(Character | CalendarEvent)[]>(() => {
|
||||
|
||||
// Filter characters
|
||||
if (isCharacter(item)) {
|
||||
const queryString = new String(searchQuery.value)
|
||||
const queryString = (searchQuery.value as string)
|
||||
.replace(searchUnifier, "")
|
||||
.toLocaleLowerCase()
|
||||
|
||||
@@ -279,7 +279,6 @@ function handleCategoryUnselect(e: Category) {
|
||||
</UiDialogDescription>
|
||||
</VisuallyHidden>
|
||||
|
||||
<!-- UiDialog header -->
|
||||
<div id="searchForm" class="grid gap-3">
|
||||
<div class="relative w-full h-fit">
|
||||
<UiInput
|
||||
@@ -307,10 +306,6 @@ function handleCategoryUnselect(e: Category) {
|
||||
<UiToggleGroupItem value="events" aria-label="Uniquement les évènements">
|
||||
{{ $t('entity.calendar.event.namePlural') }}
|
||||
</UiToggleGroupItem>
|
||||
<!-- Not used for now -->
|
||||
<!-- <UiToggleGroupItem value="characters" aria-label="Uniquement les personnages">
|
||||
{{ $t('entity.character.namePlural') }}
|
||||
</UiToggleGroupItem> -->
|
||||
</UiToggleGroup>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Character } from "~/models/Characters"
|
||||
import type { RPGDate } from "~/models/Date"
|
||||
import { useCalendar } from "~/stores/CalendarStore"
|
||||
import type { Character } from "@@/models/Characters"
|
||||
import type { RPGDate } from "@@/models/Date"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "~/components/ui/tooltip"
|
||||
import { Button } from "~/components/ui/button"
|
||||
@@ -12,7 +12,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
(e: "query:date-jump", payload: RPGDate): void
|
||||
"query:date-jump": [payload: RPGDate]
|
||||
}>()
|
||||
|
||||
const { getFormattedDateTitle } = useCalendar()
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { cn } from "~/lib/utils"
|
||||
import type { RPGDate } from "~/models/Date"
|
||||
import type { CalendarEvent } from "~/models/CalendarEvent"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { RPGDate } from "@@/models/Date"
|
||||
import type { CalendarEvent } from "@@/models/CalendarEvent"
|
||||
|
||||
import { PhArrowSquareOut, PhHourglassMedium, PhAlarm, PhMapPinArea, PhEye } from "@phosphor-icons/vue"
|
||||
|
||||
@@ -10,7 +10,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
(e: "query:date-jump", payload: RPGDate): void
|
||||
"query:date-jump": [payload: RPGDate]
|
||||
}>()
|
||||
|
||||
const { getRelativeString, defaultDate, getFormattedDateTitle } = useCalendar()
|
||||
@@ -113,9 +113,7 @@ const dateDuration = computed<string | null>(() => props.event.endDate ? getRela
|
||||
|
||||
<div v-if="event.description" class="text-xs md:text-sm">
|
||||
<hr class="my-3 md:my-2 border-white opacity-50" >
|
||||
<span class="opacity-75">
|
||||
{{ event.description }}
|
||||
</span>
|
||||
<div class="content-editor opacity-75" v-html="event.description" />
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import { isCharacter, type Character } from "~/models/Characters"
|
||||
import type { RPGDate, RPGDateOrder } from "~/models/Date"
|
||||
import { useCalendar } from "~/stores/CalendarStore"
|
||||
import { isCharacter, type Character } from "@@/models/Characters"
|
||||
import type { RPGDate, RPGDateOrder } from "@@/models/Date"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
import { computed } from "vue"
|
||||
import { isCalendarEvent, type CalendarEvent } from "~/models/CalendarEvent"
|
||||
import { isCalendarEvent, type CalendarEvent } from "@@/models/CalendarEvent"
|
||||
import type { SearchMode } from "../../SearchMode"
|
||||
|
||||
import CharacterCallout from "./CharacterCallout.vue"
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { RPGDate } from "~/models/Date"
|
||||
import type { CalendarEvent } from "~/models/CalendarEvent"
|
||||
import type { RPGDate } from "@@/models/Date"
|
||||
import type { CalendarEvent } from "@@/models/CalendarEvent"
|
||||
import { breakpointsTailwind, useElementBounding } from "@vueuse/core"
|
||||
import { storeToRefs } from "pinia"
|
||||
import { computed, ref, type ComputedRef } from "vue"
|
||||
@@ -13,7 +13,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "on-open-create-dialog", date: RPGDate): void
|
||||
"on-open-create-dialog": [date: RPGDate]
|
||||
}>()
|
||||
|
||||
const calendarTile = ref()
|
||||
@@ -81,7 +81,7 @@ const eventsNotDisplayed: ComputedRef<number> = computed<number>(() => eventsFo
|
||||
<template>
|
||||
<div
|
||||
ref="calendarTile"
|
||||
class="tile relative p-1 md:p-2 transition-colors"
|
||||
class="tile relative p-1 md:p-2 transition-all"
|
||||
:class="{
|
||||
'text-slate-300 dark:text-slate-500': props.faded,
|
||||
'text-slate-500 dark:text-slate-300': !props.faded
|
||||
@@ -93,10 +93,10 @@ const eventsNotDisplayed: ComputedRef<number> = computed<number>(() => eventsFo
|
||||
>
|
||||
<ClientOnly>
|
||||
<span
|
||||
class="inline-flex size-7 md:size-8 aspect-square items-center justify-center rounded-full border-1 md:border-2 border-transparent font-bold transition-colors group-hover:border-indigo-300 dark:group-hover:border-indigo-700"
|
||||
class="inline-flex size-7 md:size-8 aspect-square items-center justify-center rounded-full border-1 md:border-2 border-transparent font-bold transition-colors group-hover:border-primary dark:group-hover:border-primary"
|
||||
:class="{
|
||||
'text-white bg-slate-600 dark:bg-slate-800': isDefaultDate && !isSelectedDate,
|
||||
'text-white bg-indigo-500': isSelectedDate
|
||||
'bg-secondary dark:bg-slate-700': isDefaultDate && !isSelectedDate,
|
||||
'bg-primary text-primary-foreground': isSelectedDate
|
||||
}"
|
||||
>
|
||||
{{ date.day }}
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { useCalendar } from "~/stores/CalendarStore"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
import { useThrottleFn } from "@vueuse/core"
|
||||
import type { RPGDate } from "~/models/Date"
|
||||
import type { RPGDate } from "@@/models/Date"
|
||||
import { VisuallyHidden } from "radix-vue"
|
||||
|
||||
const { currentDate, decrementViewMonth, incrementViewMonth, resetSkeleton } = useCalendar()
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import type { RPGDate } from "~/models/Date"
|
||||
import type { RPGDate } from "@@/models/Date"
|
||||
import { storeToRefs } from "pinia"
|
||||
import { computed, type ComputedRef } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
|
||||
const { currentDate, defaultDate, selectDate, areDatesIdentical } = useCalendar()
|
||||
const { selectedDate, currentEvents } = storeToRefs(useCalendar())
|
||||
@@ -38,14 +39,14 @@ const hasAtLeastOneEvent = computed<boolean>(() => {
|
||||
|
||||
<template>
|
||||
<button
|
||||
class="relative grid place-items-center aspect-square rounded-full border-2 border-transparent transition-colors after:content-[''] after:absolute after:top-1 after:right-1 after:w-[.3rem] after:h-[.3rem] after:rounded-full after:transition-colors"
|
||||
:class="{
|
||||
'text-slate-500 hover:border-indigo-300 hover:text-slate-900': !isDefaultDate && !isSelectedDate,
|
||||
'font-semibold text-white bg-slate-600 dark:bg-slate-800 hover:border-indigo-400': isDefaultDate && !isSelectedDate,
|
||||
'font-semibold text-white bg-indigo-500 hover:bg-indigo-600 hover:border-indigo-500': isSelectedDate,
|
||||
'after:bg-green-600': hasAtLeastOneEvent,
|
||||
'after:bg-slate-950': hasAtLeastOneEvent && isSelectedDate
|
||||
}"
|
||||
class="relative grid place-items-center aspect-square rounded-full border-2 border-transparent transition-colors after:content-[''] after:absolute after:top-1 after:right-1 after:w-[.3rem] after:h-[.3rem] after:rounded-full after:transition-colors cursor-pointer"
|
||||
:class="cn({
|
||||
'text-foreground/75 hover:border-primary hover:text-foreground': !isDefaultDate && !isSelectedDate,
|
||||
'font-semibold text-foreground bg-secondary hover:border-primary/70': isDefaultDate && !isSelectedDate,
|
||||
'font-semibold text-primary-foreground bg-primary hover:border-primary/70': isSelectedDate,
|
||||
'after:bg-primary': hasAtLeastOneEvent,
|
||||
'after:bg-primary-foreground': hasAtLeastOneEvent && isSelectedDate
|
||||
})"
|
||||
@click="selectDate(tileDate)"
|
||||
>
|
||||
<span ref="tileRef" class="text-[.85em]">{{ dayNumber }}</span>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { useCalendar } from "~/stores/CalendarStore"
|
||||
import { useCalendar } from "@/stores/CalendarStore"
|
||||
import { useThrottleFn } from "@vueuse/core"
|
||||
|
||||
const { decrementViewYear, incrementViewYear } = useCalendar()
|
||||
@@ -24,7 +24,7 @@ const moveCalendarRight = useThrottleFn(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container mt-[10vh] mb-auto" @wheel="handleWheel">
|
||||
<div class="container mx-auto mt-[10vh] mb-auto" @wheel="handleWheel">
|
||||
<div class="grid grid-cols-5 gap-x-8 gap-y-16">
|
||||
<CalendarStateYearlyMonthTile
|
||||
v-for="month in months"
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { CalendarMonth } from "~/models/CalendarMonth";
|
||||
import type { CalendarMonth } from "@@/models/CalendarMonth";
|
||||
|
||||
defineProps<{
|
||||
month: CalendarMonth
|
||||
@@ -11,7 +11,7 @@ defineProps<{
|
||||
<div class="font-medium">
|
||||
{{ month.name }}
|
||||
</div>
|
||||
<div class="grid grid-cols-7 gap-1">
|
||||
<div class="grid grid-cols-7">
|
||||
<CalendarStateYearlyDayTile
|
||||
v-for="day in month.days"
|
||||
:key="day"
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface SpacingProps {
|
||||
size?: "xs" | "sm" | "md" | "lg" | "xlg" | "2xl" | "3xl"
|
||||
22
app/components/global/card/Error.vue
Normal file
22
app/components/global/card/Error.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script lang="ts" setup>
|
||||
import { PhCloudX } from '@phosphor-icons/vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UiCard class="w-full h-full flex flex-col border-rose-200 bg-rose-50 dark:border-rose-900 dark:bg-rose-950">
|
||||
<template v-if="$slots.title">
|
||||
<UiCardHeader class="flex-row items-center gap-2">
|
||||
<PhCloudX :size="32"/>
|
||||
|
||||
<UiCardTitle>
|
||||
<slot name="title" />
|
||||
</UiCardTitle>
|
||||
</UiCardHeader>
|
||||
</template>
|
||||
<template v-if="$slots.content">
|
||||
<UiCardContent class="grow grid gap-2">
|
||||
<slot name="content" />
|
||||
</UiCardContent>
|
||||
</template>
|
||||
</UiCard>
|
||||
</template>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { cn } from "~/lib/utils";
|
||||
import { type RPGColor, rpgColors } from "~/models/Color";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { type RPGColor, rpgColors } from "@@/models/Color";
|
||||
|
||||
const { id, theme = "normal", position = "popper" } = defineProps<{
|
||||
id: string
|
||||
@@ -13,7 +13,15 @@ const model = defineModel<RPGColor>({ default: "white" });
|
||||
|
||||
<template>
|
||||
<UiSelect v-model="model">
|
||||
<UiSelectTrigger :id :class="cn({ 'h-9': theme === 'subtle' })">
|
||||
<UiSelectTrigger
|
||||
:id
|
||||
:class="cn(
|
||||
['hover:bg-secondary hover:text-primary-foreground'],
|
||||
{
|
||||
'h-9': theme === 'subtle'
|
||||
}
|
||||
)"
|
||||
>
|
||||
<UiSelectValue
|
||||
:placeholder="$t('ui.colors.selectOne')"
|
||||
class="bgc"
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { contentStates, type ContentState } from "~/models/Entity";
|
||||
import { contentStates, type ContentState } from "@@/models/Entity";
|
||||
|
||||
defineProps<{
|
||||
id: string
|
||||
244
app/components/global/input/Editor.vue
Normal file
244
app/components/global/input/Editor.vue
Normal file
@@ -0,0 +1,244 @@
|
||||
<script lang="ts" setup>
|
||||
import { useEditor, EditorContent, type Content } from '@tiptap/vue-3'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import { PhArrowUDownRight, PhArrowUUpLeft, PhListBullets, PhListNumbers, PhQuotes, PhTextB, PhTextItalic, PhTextStrikethrough, PhTextTSlash } from '@phosphor-icons/vue'
|
||||
|
||||
const props = defineProps<{
|
||||
disableInlines?: boolean
|
||||
disableBlocks?: boolean
|
||||
}>()
|
||||
|
||||
const model = defineModel<any>()
|
||||
|
||||
const editor = useEditor({
|
||||
content: model.value as Content,
|
||||
extensions: [
|
||||
StarterKit
|
||||
],
|
||||
|
||||
onUpdate: ({ editor }) => {
|
||||
model.value = editor.getHTML()
|
||||
}
|
||||
})
|
||||
|
||||
function clearFormatting() {
|
||||
editor.value?.chain().focus().unsetAllMarks().run()
|
||||
editor.value?.chain().focus().clearNodes().run()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<!-- Toolbar -->
|
||||
<div class="flex gap-1.5">
|
||||
<!-- Inline styles -->
|
||||
<div class="flex" v-if="!props.disableInlines">
|
||||
<UiButton
|
||||
@click.prevent="editor.chain().focus().toggleBold().run()"
|
||||
:disabled="!editor.can().chain().focus().toggleBold().run()"
|
||||
:variant="editor.isActive('bold') ? 'default' : 'secondary'"
|
||||
class="size-7 rounded-e-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhTextB weight="bold" />
|
||||
</UiButton>
|
||||
|
||||
<UiButton
|
||||
@click.prevent="editor.chain().focus().toggleItalic().run()"
|
||||
:disabled="!editor.can().chain().focus().toggleItalic().run()"
|
||||
:variant="editor.isActive('italic') ? 'default' : 'secondary'"
|
||||
class="size-7 rounded-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhTextItalic weight="bold" />
|
||||
</UiButton>
|
||||
|
||||
<UiButton
|
||||
@click.prevent="editor.chain().focus().toggleStrike().run()"
|
||||
:disabled="!editor.can().chain().focus().toggleStrike().run()"
|
||||
:variant="editor.isActive('strike') ? 'default' : 'secondary'"
|
||||
class="size-7 rounded-s-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhTextStrikethrough weight="bold" />
|
||||
</UiButton>
|
||||
</div>
|
||||
|
||||
<!-- Block styles -->
|
||||
<div class="flex" v-if="!props.disableBlocks">
|
||||
<UiButton
|
||||
@click.prevent="editor.chain().focus().toggleBulletList().run()"
|
||||
:variant="editor.isActive('bulletList') ? 'default' : 'secondary'"
|
||||
class="size-7 rounded-e-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhListBullets weight="bold" />
|
||||
</UiButton>
|
||||
|
||||
<UiButton
|
||||
@click.prevent="editor.chain().focus().toggleOrderedList().run()"
|
||||
:variant="editor.isActive('orderedList') ? 'default' : 'secondary'"
|
||||
class="size-7 rounded-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhListNumbers weight="bold" />
|
||||
</UiButton>
|
||||
|
||||
<UiButton
|
||||
@click.prevent="editor.chain().focus().toggleBlockquote().run()"
|
||||
:variant="editor.isActive('blockquote') ? 'default' : 'secondary'"
|
||||
class="size-7 rounded-s-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhQuotes weight="fill" />
|
||||
</UiButton>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<UiButton
|
||||
@click.prevent="clearFormatting"
|
||||
variant="secondary"
|
||||
class="size-7 rounded-e-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhTextTSlash weight="bold" />
|
||||
</UiButton>
|
||||
|
||||
<UiButton
|
||||
@click.prevent="editor.chain().focus().undo().run()"
|
||||
:disabled="!editor.can().chain().focus().undo().run()"
|
||||
variant="secondary"
|
||||
class="size-7 rounded-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhArrowUUpLeft weight="bold" />
|
||||
</UiButton>
|
||||
|
||||
<UiButton
|
||||
@click.prevent="editor.chain().focus().redo().run()"
|
||||
:disabled="!editor.can().chain().focus().redo().run()"
|
||||
variant="secondary"
|
||||
class="size-7 rounded-s-none"
|
||||
size="icon"
|
||||
>
|
||||
<PhArrowUDownRight weight="bold" />
|
||||
</UiButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EditorContent
|
||||
:editor
|
||||
class="overflow-y-auto md:text-sm border-b-1 border-border"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.tiptap,
|
||||
.content-editor {
|
||||
/* List styles */
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
padding-block: 0.75rem;
|
||||
min-height: 7rem;
|
||||
max-height: 12rem;
|
||||
overflow-y: auto;
|
||||
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { PhCompass, PhGlobeHemisphereEast, PhHurricane, PhX } from "@phosphor-icons/vue"
|
||||
import { PhCompass, PhGlobeHemisphereEast, PhHurricane, PhInfo, PhX } from "@phosphor-icons/vue"
|
||||
import type { SidebarMenuActionType, SidebarMenuIcon } from "./SidebarProps";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { breakpointsTailwind } from "@vueuse/core"
|
||||
|
||||
const { revealAdvancedSearch } = useCalendar()
|
||||
@@ -40,13 +40,13 @@ const breakpoints = useBreakpoints(
|
||||
<nav
|
||||
ref="sidebarRef"
|
||||
:class="cn(
|
||||
['md:relative md:isolate w-16 py-6 grid gap-4 grid-rows-[1fr_auto] justify-center transition-all'], // Base appearance
|
||||
['after:opacity-50 after:contrast-125 dark:after:opacity-75 dark:after:contrast-175 after:-hue-rotate-60'], // After styling
|
||||
['border-r-[1px] bg-indigo-700 dark:bg-black text-white border-r-indigo-700 dark:border-r-indigo-950 shadow-navbar-light dark:shadow-navbar-dark'], // Colours
|
||||
['max-md:justify-stretch max-md:px-4 max-md:py-4 max-md:absolute max-md:left-0 max-md:inset-0 max-md:z-50 max-md:w-30 max-md:max-w-full'], // Responsive behaviours
|
||||
['md:relative md:isolate w-16 py-6 grid gap-4 grid-rows-[1fr_auto] justify-center md:transition-colors'], // Base appearance
|
||||
['after:opacity-50 after:contrast-125 dark:after:opacity-75'], // After styling
|
||||
['border-r-[1px] border-r-border dark:border-r-border'], // Colours
|
||||
['max-md:justify-stretch max-md:px-4 max-md:py-4 max-md:absolute max-md:left-0 max-md:inset-0 max-md:z-50 max-md:w-40 max-md:max-w-full max-md:transition-all'], // Responsive behaviours
|
||||
{
|
||||
'max-md:-translate-x-30': !isSidebarOpened,
|
||||
'max-md:-translate-x-0 shadow-navbar-dark dark:bg-slate-950': isSidebarOpened
|
||||
'max-md:-translate-x-40': !isSidebarOpened,
|
||||
'max-md:-translate-x-0': isSidebarOpened
|
||||
}
|
||||
)"
|
||||
>
|
||||
@@ -72,11 +72,11 @@ const breakpoints = useBreakpoints(
|
||||
class="rounded-full max-md:hidden"
|
||||
as-child
|
||||
>
|
||||
<RouterLink to="/explore">
|
||||
<NuxtLink to="/explore">
|
||||
<PhCompass size="24" weight="fill" />
|
||||
</RouterLink>
|
||||
</NuxtLink>
|
||||
</UiButton>
|
||||
<RouterLink
|
||||
<NuxtLink
|
||||
to="/explore"
|
||||
class="md:hidden flex items-center gap-[.6ch] underline-offset-4 hover:underline"
|
||||
>
|
||||
@@ -85,7 +85,7 @@ const breakpoints = useBreakpoints(
|
||||
<span class="text-[.9em]">
|
||||
{{ $t('pages.explore.menuLabel') }}
|
||||
</span>
|
||||
</RouterLink>
|
||||
</NuxtLink>
|
||||
</UiTooltipTrigger>
|
||||
<UiTooltipContent :side="'right'" :side-offset="6">
|
||||
<p>
|
||||
@@ -108,9 +108,9 @@ const breakpoints = useBreakpoints(
|
||||
class="rounded-full"
|
||||
as-child
|
||||
>
|
||||
<RouterLink :to="item.to">
|
||||
<NuxtLink :to="item.to">
|
||||
<component :is="computeMenuItemIcon(item.phIcon)" size="24" :weight="item.phIconWeight || 'fill'" />
|
||||
</RouterLink>
|
||||
</NuxtLink>
|
||||
</UiButton>
|
||||
<UiButton
|
||||
v-if="item.action"
|
||||
@@ -134,23 +134,3 @@ const breakpoints = useBreakpoints(
|
||||
<UserCTA />
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
nav {
|
||||
&::after {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
inset-inline: 0;
|
||||
height: 25rem;
|
||||
max-height: 100%;
|
||||
background-image: url("/images/sidebar.png");
|
||||
background-position: bottom;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
mask-image: linear-gradient(to top, black 25%, transparent 50%, transparent);
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,7 @@
|
||||
import { computed } from "vue"
|
||||
|
||||
import { PhCheckCircle, PhUser, PhLaptop, PhMoon, PhPalette, PhSignIn, PhSignOut, PhSun, PhTranslate, PhUserCircle } from "@phosphor-icons/vue"
|
||||
import { cn } from "~/lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@@ -57,8 +57,14 @@ function pushRoute(to: AvailableRoutes) {
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<UiDropdownMenu v-model:open="menuOpened">
|
||||
<UiDropdownMenuTrigger>
|
||||
<UiAvatar v-if="user" id="user-avatar" class="ring-[.2rem] ring-indigo-700 dark:ring-neutral-900 cursor-pointer">
|
||||
<UiDropdownMenuTrigger class="aspect-square">
|
||||
<TransitionGroup name="fade-group" appear>
|
||||
<UiAvatar
|
||||
v-if="user"
|
||||
id="user-avatar"
|
||||
class="ring-[.2rem] ring-primary hover:bg-accent hover:ring-accent transition-all cursor-pointer"
|
||||
:class="cn({ 'ring-accent bg-accent dark:bg-accent': menuOpened })"
|
||||
>
|
||||
<UiAvatarImage
|
||||
:src="userMeta?.avatar_url"
|
||||
:alt="userMeta?.full_name"
|
||||
@@ -68,9 +74,16 @@ function pushRoute(to: AvailableRoutes) {
|
||||
{{ $t('ui.sidebarMenu.avatarFallback') }}
|
||||
</UiAvatarFallback>
|
||||
</UiAvatar>
|
||||
<UiButton v-else variant="outline" size="icon" class="rounded-full border-indigo-200 bg-indigo-700 dark:border-slate-300 dark:bg-neutral-950 dark:hover:bg-slate-50 dark:hover:text-slate-950 cursor-pointer">
|
||||
<UiButton
|
||||
v-else
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="ring-[.2rem] ring-primary hover:bg-accent hover:ring-accent border-none dark:bg-background rounded-full bg-primary transition-all cursor-pointer"
|
||||
:class="cn({ 'ring-accent bg-accent dark:bg-accent': menuOpened })"
|
||||
>
|
||||
<PhUserCircle size="24" />
|
||||
</UiButton>
|
||||
</TransitionGroup>
|
||||
</UiDropdownMenuTrigger>
|
||||
|
||||
<UiDropdownMenuContent class="w-72 p-0 pb-1" :align="'start'" :side="'top'" :side-offset="10" :align-offset="25" :collision-padding="40">
|
||||
@@ -184,12 +197,6 @@ function pushRoute(to: AvailableRoutes) {
|
||||
<UiDropdownMenuSeparator />
|
||||
|
||||
<template v-if="user">
|
||||
<!-- <UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="pushRoute('/my/settings')">
|
||||
<PhGear size="20" weight="fill" />
|
||||
<span>
|
||||
{{ $t('ui.sidebarMenu.account') }}
|
||||
</span>
|
||||
</UiDropdownMenuItem> -->
|
||||
<UiDropdownMenuItem class="flex gap-[.5ch] items-center rounded-none" @click="handleLogout">
|
||||
<PhSignOut size="20" weight="fill" />
|
||||
<span>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from "vue"
|
||||
import { AlertDialogAction, type AlertDialogActionProps } from "radix-vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "~/components/ui/button/index"
|
||||
|
||||
const props = defineProps<AlertDialogActionProps & { class?: HTMLAttributes["class"] }>()
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from "vue"
|
||||
import { AlertDialogCancel, type AlertDialogCancelProps } from "radix-vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "~/components/ui/button/index"
|
||||
|
||||
const props = defineProps<AlertDialogCancelProps & { class?: HTMLAttributes["class"] }>()
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
AlertDialogPortal,
|
||||
useForwardPropsEmits,
|
||||
} from "radix-vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<AlertDialogContentProps & { class?: HTMLAttributes["class"] }>()
|
||||
const emits = defineEmits<AlertDialogContentEmits>()
|
||||
@@ -31,7 +31,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
v-bind="forwarded"
|
||||
:class="
|
||||
cn(
|
||||
'fixed left-1/2 top-1/2 z-50 grid w-[calc(100%-2rem)] max-w-3xl -translate-x-1/2 -translate-y-1/2 gap-4 border border-indigo-200 bg-background dark:bg-slate-950 dark:border-indigo-950 p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-50% data-[state=closed]:slide-out-to-top-48% data-[state=open]:slide-in-from-left-50% data-[state=open]:slide-in-from-top-48% rounded-lg',
|
||||
'fixed left-1/2 top-1/2 z-50 grid w-[calc(100%-2rem)] max-w-3xl -translate-x-1/2 -translate-y-1/2 gap-4 border border-popover-border bg-popover p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-50% data-[state=closed]:slide-out-to-top-48% data-[state=open]:slide-in-from-left-50% data-[state=open]:slide-in-from-top-48% rounded-lg',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
AlertDialogDescription,
|
||||
type AlertDialogDescriptionProps,
|
||||
} from "radix-vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<AlertDialogDescriptionProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from "vue"
|
||||
import { AlertDialogTitle, type AlertDialogTitleProps } from "radix-vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<AlertDialogTitleProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
9
app/components/ui/alert-dialog/index.ts
Normal file
9
app/components/ui/alert-dialog/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export { default as AlertDialog } from "@/components/ui/alert-dialog/AlertDialog.vue"
|
||||
export { default as AlertDialogTrigger } from "@/components/ui/alert-dialog/AlertDialogTrigger.vue"
|
||||
export { default as AlertDialogContent } from "@/components/ui/alert-dialog/AlertDialogContent.vue"
|
||||
export { default as AlertDialogHeader } from "@/components/ui/alert-dialog/AlertDialogHeader.vue"
|
||||
export { default as AlertDialogTitle } from "@/components/ui/alert-dialog/AlertDialogTitle.vue"
|
||||
export { default as AlertDialogDescription } from "@/components/ui/alert-dialog/AlertDialogDescription.vue"
|
||||
export { default as AlertDialogFooter } from "@/components/ui/alert-dialog/AlertDialogFooter.vue"
|
||||
export { default as AlertDialogAction } from "@/components/ui/alert-dialog/AlertDialogAction.vue"
|
||||
export { default as AlertDialogCancel } from "@/components/ui/alert-dialog/AlertDialogCancel.vue"
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { AvatarRoot } from "radix-vue"
|
||||
import { type AvatarVariants, avatarVariant } from "."
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -1,8 +1,8 @@
|
||||
import { type VariantProps, cva } from "class-variance-authority"
|
||||
|
||||
export { default as Avatar } from "./Avatar.vue"
|
||||
export { default as AvatarImage } from "./AvatarImage.vue"
|
||||
export { default as AvatarFallback } from "./AvatarFallback.vue"
|
||||
export { default as Avatar } from "@/components/ui/avatar/Avatar.vue"
|
||||
export { default as AvatarImage } from "@/components/ui/avatar/AvatarImage.vue"
|
||||
export { default as AvatarFallback } from "@/components/ui/avatar/AvatarFallback.vue"
|
||||
|
||||
export const avatarVariant = cva(
|
||||
"inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden",
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { type BadgeVariants, badgeVariants } from "."
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
variant?: BadgeVariants["variant"]
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type VariantProps, cva } from "class-variance-authority"
|
||||
|
||||
export { default as Badge } from "./Badge.vue"
|
||||
export { default as Badge } from "@/components/ui/badge/Badge.vue"
|
||||
|
||||
export const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { PhArrowsHorizontal } from "@phosphor-icons/vue";
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { PrimitiveProps } from "radix-vue"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Primitive } from "radix-vue"
|
||||
|
||||
const props = withDefaults(defineProps<PrimitiveProps & { class?: HTMLAttributes["class"] }>(), {
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -9,7 +9,7 @@ const props = defineProps<{
|
||||
|
||||
<template>
|
||||
<ol
|
||||
:class="cn('flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5', props.class)"
|
||||
:class="cn('flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground transition-colors sm:gap-2.5', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</ol>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -12,7 +12,7 @@ const props = defineProps<{
|
||||
role="link"
|
||||
aria-disabled="true"
|
||||
aria-current="page"
|
||||
:class="cn('font-normal text-foreground', props.class)"
|
||||
:class="cn('font-normal text-foreground transition-colors', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { PhCaretRight } from "@phosphor-icons/vue";
|
||||
|
||||
const props = defineProps<{
|
||||
7
app/components/ui/breadcrumb/index.ts
Normal file
7
app/components/ui/breadcrumb/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export { default as Breadcrumb } from "@/components/ui/breadcrumb/Breadcrumb.vue"
|
||||
export { default as BreadcrumbEllipsis } from "@/components/ui/breadcrumb/BreadcrumbEllipsis.vue"
|
||||
export { default as BreadcrumbItem } from "@/components/ui/breadcrumb/BreadcrumbItem.vue"
|
||||
export { default as BreadcrumbLink } from "@/components/ui/breadcrumb/BreadcrumbLink.vue"
|
||||
export { default as BreadcrumbList } from "@/components/ui/breadcrumb/BreadcrumbList.vue"
|
||||
export { default as BreadcrumbPage } from "@/components/ui/breadcrumb/BreadcrumbPage.vue"
|
||||
export { default as BreadcrumbSeparator } from "@/components/ui/breadcrumb/BreadcrumbSeparator.vue"
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { Primitive, type PrimitiveProps } from "radix-vue"
|
||||
import { type ButtonVariants, buttonVariants } from "."
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
interface Props extends PrimitiveProps {
|
||||
variant?: ButtonVariants["variant"]
|
||||
@@ -1,17 +1,17 @@
|
||||
import { type VariantProps, cva } from "class-variance-authority"
|
||||
|
||||
export { default as Button } from "./Button.vue"
|
||||
export { default as Button } from "@/components/ui/button/Button.vue"
|
||||
|
||||
export const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-30",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/70",
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline: "border border-input hover:bg-accent hover:text-accent-foreground",
|
||||
outline: "border border-input hover:bg-primary hover:text-primary-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-primary/20",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
ghost: "hover:bg-primary/70 hover:text-primary-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline"
|
||||
},
|
||||
size: {
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user