WIP: Redesign app layout chrome #105
+270
-78
@@ -1,6 +1,6 @@
|
||||
@import 'tailwindcss';
|
||||
@import "tailwindcss";
|
||||
|
||||
@import 'tw-animate-css';
|
||||
@import "tw-animate-css";
|
||||
|
||||
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
|
||||
@source '../../storage/framework/views/*.php';
|
||||
@@ -9,13 +9,69 @@
|
||||
|
||||
@theme inline {
|
||||
--font-sans:
|
||||
Instrument Sans, ui-sans-serif, system-ui, sans-serif,
|
||||
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||
'Noto Color Emoji';
|
||||
Inter, Instrument Sans, ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
--font-headline-lg:
|
||||
Inter, Instrument Sans, ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
--font-headline-lg-mobile:
|
||||
Inter, Instrument Sans, ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
--font-headline-md:
|
||||
Inter, Instrument Sans, ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
--font-body-md:
|
||||
Inter, Instrument Sans, ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
--font-body-sm:
|
||||
Inter, Instrument Sans, ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
--font-label-uppercase:
|
||||
Inter, Instrument Sans, ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
|
||||
--radius-lg: var(--radius);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-sm: 0.125rem;
|
||||
--radius-md: 0.375rem;
|
||||
--radius-lg: 0.5rem;
|
||||
--radius-xl: 0.75rem;
|
||||
|
||||
--spacing-container-margin: 1.5rem;
|
||||
--spacing-column-gap: 1rem;
|
||||
--spacing-card-padding: 0.75rem;
|
||||
--spacing-stack-gap-sm: 0.5rem;
|
||||
--spacing-stack-gap-md: 0.75rem;
|
||||
|
||||
--text-headline-lg: 1.5rem;
|
||||
--text-headline-lg--line-height: 2rem;
|
||||
--text-headline-lg--font-weight: 600;
|
||||
--text-headline-lg--letter-spacing: 0;
|
||||
--text-headline-md: 1.125rem;
|
||||
--text-headline-md--line-height: 1.5rem;
|
||||
--text-headline-md--font-weight: 600;
|
||||
--text-headline-md--letter-spacing: 0;
|
||||
--text-headline-lg-mobile: 1.25rem;
|
||||
--text-headline-lg-mobile--line-height: 1.75rem;
|
||||
--text-headline-lg-mobile--font-weight: 600;
|
||||
--text-body-md: 0.875rem;
|
||||
--text-body-md--line-height: 1.25rem;
|
||||
--text-body-md--font-weight: 400;
|
||||
--text-body-sm: 0.8125rem;
|
||||
--text-body-sm--line-height: 1.125rem;
|
||||
--text-body-sm--font-weight: 400;
|
||||
--text-label-uppercase: 0.6875rem;
|
||||
--text-label-uppercase--line-height: 1rem;
|
||||
--text-label-uppercase--font-weight: 700;
|
||||
--text-label-uppercase--letter-spacing: 0.05em;
|
||||
|
||||
--shadow-kanban-card: 0 4px 12px rgb(0 0 0 / 0.08);
|
||||
--shadow-kanban-nav: 0 12px 30px rgb(15 23 42 / 0.06);
|
||||
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
@@ -59,6 +115,54 @@
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
|
||||
--color-surface: var(--surface);
|
||||
--color-surface-dim: var(--surface-dim);
|
||||
--color-surface-bright: var(--surface-bright);
|
||||
--color-surface-container-lowest: var(--surface-container-lowest);
|
||||
--color-surface-container-low: var(--surface-container-low);
|
||||
--color-surface-container: var(--surface-container);
|
||||
--color-surface-container-high: var(--surface-container-high);
|
||||
--color-surface-container-highest: var(--surface-container-highest);
|
||||
--color-surface-variant: var(--surface-variant);
|
||||
--color-surface-tint: var(--surface-tint);
|
||||
--color-on-surface: var(--on-surface);
|
||||
--color-on-surface-variant: var(--on-surface-variant);
|
||||
--color-on-background: var(--on-background);
|
||||
--color-outline: var(--outline);
|
||||
--color-outline-variant: var(--outline-variant);
|
||||
--color-primary-container: var(--primary-container);
|
||||
--color-on-primary: var(--on-primary);
|
||||
--color-on-primary-container: var(--on-primary-container);
|
||||
--color-primary-fixed: var(--primary-fixed);
|
||||
--color-primary-fixed-dim: var(--primary-fixed-dim);
|
||||
--color-on-primary-fixed: var(--on-primary-fixed);
|
||||
--color-on-primary-fixed-variant: var(--on-primary-fixed-variant);
|
||||
--color-secondary-container: var(--secondary-container);
|
||||
--color-on-secondary: var(--on-secondary);
|
||||
--color-on-secondary-container: var(--on-secondary-container);
|
||||
--color-secondary-fixed: var(--secondary-fixed);
|
||||
--color-secondary-fixed-dim: var(--secondary-fixed-dim);
|
||||
--color-on-secondary-fixed: var(--on-secondary-fixed);
|
||||
--color-on-secondary-fixed-variant: var(--on-secondary-fixed-variant);
|
||||
--color-tertiary: var(--tertiary);
|
||||
--color-tertiary-container: var(--tertiary-container);
|
||||
--color-on-tertiary: var(--on-tertiary);
|
||||
--color-on-tertiary-container: var(--on-tertiary-container);
|
||||
--color-tertiary-fixed: var(--tertiary-fixed);
|
||||
--color-tertiary-fixed-dim: var(--tertiary-fixed-dim);
|
||||
--color-on-tertiary-fixed: var(--on-tertiary-fixed);
|
||||
--color-on-tertiary-fixed-variant: var(--on-tertiary-fixed-variant);
|
||||
--color-error: var(--error);
|
||||
--color-error-container: var(--error-container);
|
||||
--color-on-error: var(--on-error);
|
||||
--color-on-error-container: var(--on-error-container);
|
||||
--color-inverse-surface: var(--inverse-surface);
|
||||
--color-inverse-on-surface: var(--inverse-on-surface);
|
||||
--color-inverse-primary: var(--inverse-primary);
|
||||
--color-priority-high: #ef4444;
|
||||
--color-priority-medium: #f59e0b;
|
||||
--color-priority-low: #3b82f6;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -83,83 +187,171 @@
|
||||
body,
|
||||
html {
|
||||
--font-sans:
|
||||
'Instrument Sans', ui-sans-serif, system-ui, sans-serif,
|
||||
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||
'Noto Color Emoji';
|
||||
Inter, "Instrument Sans", ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
--background: hsl(0 0% 100%);
|
||||
--foreground: hsl(0 0% 3.9%);
|
||||
--card: hsl(0 0% 100%);
|
||||
--card-foreground: hsl(0 0% 3.9%);
|
||||
--popover: hsl(0 0% 100%);
|
||||
--popover-foreground: hsl(0 0% 3.9%);
|
||||
--primary: hsl(0 0% 9%);
|
||||
--primary-foreground: hsl(0 0% 98%);
|
||||
--secondary: hsl(0 0% 92.1%);
|
||||
--secondary-foreground: hsl(0 0% 9%);
|
||||
--muted: hsl(0 0% 96.1%);
|
||||
--muted-foreground: hsl(0 0% 45.1%);
|
||||
--accent: hsl(0 0% 96.1%);
|
||||
--accent-foreground: hsl(0 0% 9%);
|
||||
--destructive: hsl(0 84.2% 60.2%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(0 0% 92.8%);
|
||||
--input: hsl(0 0% 89.8%);
|
||||
--ring: hsl(0 0% 3.9%);
|
||||
--chart-1: hsl(12 76% 61%);
|
||||
--chart-2: hsl(173 58% 39%);
|
||||
--chart-3: hsl(197 37% 24%);
|
||||
--chart-4: hsl(43 74% 66%);
|
||||
--chart-5: hsl(27 87% 67%);
|
||||
--radius: 0.5rem;
|
||||
--sidebar-background: hsl(0 0% 98%);
|
||||
--sidebar-foreground: hsl(240 5.3% 26.1%);
|
||||
--sidebar-primary: hsl(0 0% 10%);
|
||||
--sidebar-primary-foreground: hsl(0 0% 98%);
|
||||
--sidebar-accent: hsl(0 0% 94%);
|
||||
--sidebar-accent-foreground: hsl(0 0% 30%);
|
||||
--sidebar-border: hsl(0 0% 91%);
|
||||
--sidebar-ring: hsl(217.2 91.2% 59.8%);
|
||||
--sidebar: hsl(0 0% 98%);
|
||||
--background: #f7f9fb;
|
||||
--foreground: #191c1e;
|
||||
--card: #ffffff;
|
||||
--card-foreground: #191c1e;
|
||||
--popover: #ffffff;
|
||||
--popover-foreground: #191c1e;
|
||||
--primary: #006e2f;
|
||||
--primary-foreground: #ffffff;
|
||||
--secondary: #d0e1fb;
|
||||
--secondary-foreground: #0b1c30;
|
||||
--muted: #f2f4f6;
|
||||
--muted-foreground: #3d4a3d;
|
||||
--accent: #e6e8ea;
|
||||
--accent-foreground: #191c1e;
|
||||
--destructive: #ba1a1a;
|
||||
--destructive-foreground: #ffffff;
|
||||
--border: #bccbb9;
|
||||
--input: #bccbb9;
|
||||
--ring: #006e2f;
|
||||
--chart-1: #22c55e;
|
||||
--chart-2: #3b82f6;
|
||||
--chart-3: #f59e0b;
|
||||
--chart-4: #ef4444;
|
||||
--chart-5: #505f76;
|
||||
--radius: 0.25rem;
|
||||
--surface: #f7f9fb;
|
||||
--surface-dim: #d8dadc;
|
||||
--surface-bright: #f7f9fb;
|
||||
--surface-container-lowest: #ffffff;
|
||||
--surface-container-low: #f2f4f6;
|
||||
--surface-container: #eceef0;
|
||||
--surface-container-high: #e6e8ea;
|
||||
--surface-container-highest: #e0e3e5;
|
||||
--surface-variant: #e0e3e5;
|
||||
--surface-tint: #006e2f;
|
||||
--on-surface: #191c1e;
|
||||
--on-surface-variant: #3d4a3d;
|
||||
--on-background: #191c1e;
|
||||
--outline: #6d7b6c;
|
||||
--outline-variant: #bccbb9;
|
||||
--primary-container: #22c55e;
|
||||
--on-primary: #ffffff;
|
||||
--on-primary-container: #004b1e;
|
||||
--primary-fixed: #6bff8f;
|
||||
--primary-fixed-dim: #4ae176;
|
||||
--on-primary-fixed: #002109;
|
||||
--on-primary-fixed-variant: #005321;
|
||||
--secondary-container: #d0e1fb;
|
||||
--on-secondary: #ffffff;
|
||||
--on-secondary-container: #54647a;
|
||||
--secondary-fixed: #d3e4fe;
|
||||
--secondary-fixed-dim: #b7c8e1;
|
||||
--on-secondary-fixed: #0b1c30;
|
||||
--on-secondary-fixed-variant: #38485d;
|
||||
--tertiary: #9e4036;
|
||||
--tertiary-container: #ff8b7c;
|
||||
--on-tertiary: #ffffff;
|
||||
--on-tertiary-container: #76231b;
|
||||
--tertiary-fixed: #ffdad5;
|
||||
--tertiary-fixed-dim: #ffb4a9;
|
||||
--on-tertiary-fixed: #410001;
|
||||
--on-tertiary-fixed-variant: #7f2a21;
|
||||
--error: #ba1a1a;
|
||||
--error-container: #ffdad6;
|
||||
--on-error: #ffffff;
|
||||
--on-error-container: #93000a;
|
||||
--inverse-surface: #2d3133;
|
||||
--inverse-on-surface: #eff1f3;
|
||||
--inverse-primary: #4ae176;
|
||||
--sidebar-background: #f2f4f6;
|
||||
--sidebar-foreground: #191c1e;
|
||||
--sidebar-primary: #006e2f;
|
||||
--sidebar-primary-foreground: #ffffff;
|
||||
--sidebar-accent: #e6e8ea;
|
||||
--sidebar-accent-foreground: #191c1e;
|
||||
--sidebar-border: #bccbb9;
|
||||
--sidebar-ring: #006e2f;
|
||||
--sidebar: #f2f4f6;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: hsl(0 0% 3.9%);
|
||||
--foreground: hsl(0 0% 98%);
|
||||
--card: hsl(0 0% 3.9%);
|
||||
--card-foreground: hsl(0 0% 98%);
|
||||
--popover: hsl(0 0% 3.9%);
|
||||
--popover-foreground: hsl(0 0% 98%);
|
||||
--primary: hsl(0 0% 98%);
|
||||
--primary-foreground: hsl(0 0% 9%);
|
||||
--secondary: hsl(0 0% 14.9%);
|
||||
--secondary-foreground: hsl(0 0% 98%);
|
||||
--muted: hsl(0 0% 16.08%);
|
||||
--muted-foreground: hsl(0 0% 63.9%);
|
||||
--accent: hsl(0 0% 14.9%);
|
||||
--accent-foreground: hsl(0 0% 98%);
|
||||
--destructive: hsl(0 84% 60%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(0 0% 14.9%);
|
||||
--input: hsl(0 0% 14.9%);
|
||||
--ring: hsl(0 0% 83.1%);
|
||||
--chart-1: hsl(220 70% 50%);
|
||||
--chart-2: hsl(160 60% 45%);
|
||||
--chart-3: hsl(30 80% 55%);
|
||||
--chart-4: hsl(280 65% 60%);
|
||||
--chart-5: hsl(340 75% 55%);
|
||||
--sidebar-background: hsl(0 0% 7%);
|
||||
--sidebar-foreground: hsl(0 0% 95.9%);
|
||||
--sidebar-primary: hsl(360, 100%, 100%);
|
||||
--sidebar-primary-foreground: hsl(0 0% 100%);
|
||||
--sidebar-accent: hsl(0 0% 15.9%);
|
||||
--sidebar-accent-foreground: hsl(240 4.8% 95.9%);
|
||||
--sidebar-border: hsl(0 0% 15.9%);
|
||||
--sidebar-ring: hsl(217.2 91.2% 59.8%);
|
||||
--sidebar: hsl(240 5.9% 10%);
|
||||
--background: #0f172a;
|
||||
--foreground: #eff1f3;
|
||||
--card: #111827;
|
||||
--card-foreground: #eff1f3;
|
||||
--popover: #111827;
|
||||
--popover-foreground: #eff1f3;
|
||||
--primary: #4ae176;
|
||||
--primary-foreground: #002109;
|
||||
--secondary: #1f2937;
|
||||
--secondary-foreground: #eff1f3;
|
||||
--muted: #1e293b;
|
||||
--muted-foreground: #cbd5e1;
|
||||
--accent: #1e293b;
|
||||
--accent-foreground: #eff1f3;
|
||||
--destructive: #f87171;
|
||||
--destructive-foreground: #ffffff;
|
||||
--border: #334155;
|
||||
--input: #334155;
|
||||
--ring: #4ae176;
|
||||
--chart-1: #4ae176;
|
||||
--chart-2: #60a5fa;
|
||||
--chart-3: #fbbf24;
|
||||
--chart-4: #f87171;
|
||||
--chart-5: #b7c8e1;
|
||||
--surface: #0f172a;
|
||||
--surface-dim: #020617;
|
||||
--surface-bright: #111827;
|
||||
--surface-container-lowest: #111827;
|
||||
--surface-container-low: #1e293b;
|
||||
--surface-container: #263445;
|
||||
--surface-container-high: #334155;
|
||||
--surface-container-highest: #475569;
|
||||
--surface-variant: #334155;
|
||||
--surface-tint: #4ae176;
|
||||
--on-surface: #eff1f3;
|
||||
--on-surface-variant: #cbd5e1;
|
||||
--on-background: #eff1f3;
|
||||
--outline: #94a3b8;
|
||||
--outline-variant: #334155;
|
||||
--primary-container: #14532d;
|
||||
--on-primary: #002109;
|
||||
--on-primary-container: #bbf7d0;
|
||||
--primary-fixed: #6bff8f;
|
||||
--primary-fixed-dim: #4ae176;
|
||||
--on-primary-fixed: #002109;
|
||||
--on-primary-fixed-variant: #005321;
|
||||
--secondary-container: #1e3a5f;
|
||||
--on-secondary: #ffffff;
|
||||
--on-secondary-container: #d0e1fb;
|
||||
--secondary-fixed: #d3e4fe;
|
||||
--secondary-fixed-dim: #b7c8e1;
|
||||
--on-secondary-fixed: #0b1c30;
|
||||
--on-secondary-fixed-variant: #38485d;
|
||||
--tertiary: #ffb4a9;
|
||||
--tertiary-container: #7f2a21;
|
||||
--on-tertiary: #410001;
|
||||
--on-tertiary-container: #ffdad5;
|
||||
--tertiary-fixed: #ffdad5;
|
||||
--tertiary-fixed-dim: #ffb4a9;
|
||||
--on-tertiary-fixed: #410001;
|
||||
--on-tertiary-fixed-variant: #ffb4a9;
|
||||
--error: #f87171;
|
||||
--error-container: #7f1d1d;
|
||||
--on-error: #ffffff;
|
||||
--on-error-container: #fee2e2;
|
||||
--inverse-surface: #eff1f3;
|
||||
--inverse-on-surface: #191c1e;
|
||||
--inverse-primary: #006e2f;
|
||||
--sidebar-background: #111827;
|
||||
--sidebar-foreground: #eff1f3;
|
||||
--sidebar-primary: #4ae176;
|
||||
--sidebar-primary-foreground: #002109;
|
||||
--sidebar-accent: #1e293b;
|
||||
--sidebar-accent-foreground: #eff1f3;
|
||||
--sidebar-border: #334155;
|
||||
--sidebar-ring: #4ae176;
|
||||
--sidebar: #111827;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
||||
@@ -20,7 +20,7 @@ const className = computed(() => props.class);
|
||||
</SidebarInset>
|
||||
<main
|
||||
v-else
|
||||
class="mx-auto flex h-full w-full max-w-7xl flex-1 flex-col gap-4 rounded-xl"
|
||||
class="flex h-full w-full flex-1 flex-col gap-4"
|
||||
:class="className"
|
||||
>
|
||||
<slot />
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { Link, usePage } from '@inertiajs/vue3';
|
||||
import { BookOpen, Folder, LayoutGrid, Menu, Search } from 'lucide-vue-next';
|
||||
import {
|
||||
Folder,
|
||||
LayoutGrid,
|
||||
Layers3,
|
||||
Menu,
|
||||
Search,
|
||||
Shield,
|
||||
Users,
|
||||
} from 'lucide-vue-next';
|
||||
import { computed } from 'vue';
|
||||
import AppLogo from '@/components/AppLogo.vue';
|
||||
import AppLogoIcon from '@/components/AppLogoIcon.vue';
|
||||
import Breadcrumbs from '@/components/Breadcrumbs.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@@ -11,12 +18,6 @@ import {
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuList,
|
||||
navigationMenuTriggerStyle,
|
||||
} from '@/components/ui/navigation-menu';
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
@@ -24,246 +25,215 @@ import {
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@/components/ui/sheet';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import UserAvatar from '@/components/ui/avatar/UserAvatar.vue';
|
||||
import UserMenuContent from '@/components/UserMenuContent.vue';
|
||||
import { useCurrentUrl } from '@/composables/useCurrentUrl';
|
||||
import { toUrl } from '@/lib/utils';
|
||||
import { dashboard } from '@/routes/index';
|
||||
import { dashboard } from '@/routes';
|
||||
import { index as adminUsers } from '@/routes/admin/users';
|
||||
import { index as projectTemplatesIndex } from '@/routes/project-templates';
|
||||
import { index as projectsIndex } from '@/routes/projects';
|
||||
import { index as teamsIndex } from '@/routes/teams';
|
||||
import type { BreadcrumbItem, NavItem } from '@/types';
|
||||
import UserAvatar from '@/components/ui/avatar/UserAvatar.vue';
|
||||
|
||||
type Props = {
|
||||
breadcrumbs?: BreadcrumbItem[];
|
||||
};
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
breadcrumbs: () => [],
|
||||
});
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
breadcrumbs?: BreadcrumbItem[];
|
||||
}>(),
|
||||
{
|
||||
breadcrumbs: () => [],
|
||||
},
|
||||
);
|
||||
|
||||
const page = usePage();
|
||||
const auth = computed(() => page.props.auth);
|
||||
const { isCurrentUrl, whenCurrentUrl } = useCurrentUrl();
|
||||
const { isCurrentOrParentUrl } = useCurrentUrl();
|
||||
|
||||
const activeItemStyles =
|
||||
'text-neutral-900 dark:bg-neutral-800 dark:text-neutral-100';
|
||||
const mainNavItems = computed<NavItem[]>(() => {
|
||||
const items: NavItem[] = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
href: dashboard(),
|
||||
icon: LayoutGrid,
|
||||
},
|
||||
{
|
||||
title: 'Projects',
|
||||
href: projectsIndex(),
|
||||
icon: Folder,
|
||||
},
|
||||
];
|
||||
|
||||
const mainNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
href: dashboard(),
|
||||
icon: LayoutGrid,
|
||||
},
|
||||
];
|
||||
if (page.props.auth.permissions.projectCreate) {
|
||||
items.push({
|
||||
title: 'Project templates',
|
||||
href: projectTemplatesIndex(),
|
||||
icon: Layers3,
|
||||
});
|
||||
}
|
||||
|
||||
const rightNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Repository',
|
||||
href: 'https://github.com/laravel/vue-starter-kit',
|
||||
icon: Folder,
|
||||
},
|
||||
{
|
||||
title: 'Documentation',
|
||||
href: 'https://laravel.com/docs/starter-kits#vue',
|
||||
icon: BookOpen,
|
||||
},
|
||||
];
|
||||
if (page.props.auth.permissions.globalAdmin) {
|
||||
items.push({
|
||||
title: 'Users',
|
||||
href: adminUsers(),
|
||||
icon: Shield,
|
||||
});
|
||||
}
|
||||
|
||||
if (page.props.auth.permissions.canManageTeams) {
|
||||
items.push({
|
||||
title: 'Teams',
|
||||
href: teamsIndex(),
|
||||
icon: Users,
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
});
|
||||
|
||||
const navItemClasses = (item: NavItem): string =>
|
||||
[
|
||||
'inline-flex h-9 items-center gap-2 rounded-lg px-3 text-sm font-medium transition-colors duration-200',
|
||||
isCurrentOrParentUrl(item.href)
|
||||
? 'bg-primary text-primary-foreground shadow-[0_8px_20px_rgba(0,110,47,0.16)]'
|
||||
: 'text-on-surface-variant hover:bg-surface-container-high hover:text-on-surface',
|
||||
].join(' ');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="border-sidebar-border/80 border-b">
|
||||
<div class="mx-auto flex h-16 items-center px-4 md:max-w-7xl">
|
||||
<!-- Mobile Menu -->
|
||||
<div class="lg:hidden">
|
||||
<Sheet>
|
||||
<SheetTrigger :as-child="true">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="mr-2 h-9 w-9"
|
||||
>
|
||||
<Menu class="h-5 w-5" />
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left" class="w-[300px] p-6">
|
||||
<SheetTitle class="sr-only"
|
||||
>Navigation menu</SheetTitle
|
||||
>
|
||||
<SheetHeader class="flex justify-start text-left">
|
||||
<AppLogoIcon
|
||||
class="size-6 fill-current text-black dark:text-white"
|
||||
/>
|
||||
</SheetHeader>
|
||||
<div
|
||||
class="flex h-full flex-1 flex-col justify-between space-y-4 py-6"
|
||||
>
|
||||
<nav class="-mx-3 space-y-1">
|
||||
<Link
|
||||
v-for="item in mainNavItems"
|
||||
:key="item.title"
|
||||
:href="item.href"
|
||||
class="hover:bg-accent flex items-center gap-x-3 rounded-lg px-3 py-2 text-sm font-medium"
|
||||
:class="
|
||||
whenCurrentUrl(
|
||||
item.href,
|
||||
activeItemStyles,
|
||||
)
|
||||
"
|
||||
>
|
||||
<component
|
||||
v-if="item.icon"
|
||||
:is="item.icon"
|
||||
class="h-5 w-5"
|
||||
/>
|
||||
{{ item.title }}
|
||||
</Link>
|
||||
</nav>
|
||||
<div class="flex flex-col space-y-4">
|
||||
<a
|
||||
v-for="item in rightNavItems"
|
||||
:key="item.title"
|
||||
:href="toUrl(item.href)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center space-x-2 text-sm font-medium"
|
||||
>
|
||||
<component
|
||||
v-if="item.icon"
|
||||
:is="item.icon"
|
||||
class="h-5 w-5"
|
||||
/>
|
||||
<span>{{ item.title }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</div>
|
||||
|
||||
<Link :href="dashboard()" class="flex items-center gap-x-2">
|
||||
<AppLogo />
|
||||
</Link>
|
||||
|
||||
<!-- Desktop Menu -->
|
||||
<div class="hidden h-full lg:flex lg:flex-1">
|
||||
<NavigationMenu class="ml-10 flex h-full items-stretch">
|
||||
<NavigationMenuList
|
||||
class="flex h-full items-stretch space-x-2"
|
||||
<header
|
||||
class="border-outline-variant/80 bg-surface/90 shadow-kanban-nav sticky top-0 z-50 border-b backdrop-blur-md"
|
||||
>
|
||||
<div
|
||||
class="sm:px-container-margin flex h-16 w-full items-center gap-3 px-4"
|
||||
>
|
||||
<Sheet>
|
||||
<SheetTrigger :as-child="true">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="text-on-surface-variant hover:bg-surface-container-high hover:text-on-surface size-9 rounded-lg lg:hidden"
|
||||
>
|
||||
<Menu class="size-5" />
|
||||
<span class="sr-only">Open navigation</span>
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent
|
||||
side="left"
|
||||
class="border-outline-variant bg-surface w-[320px] p-0"
|
||||
>
|
||||
<SheetTitle class="sr-only">Navigation menu</SheetTitle>
|
||||
<SheetHeader class="border-outline-variant border-b p-4">
|
||||
<Link
|
||||
:href="dashboard()"
|
||||
class="flex items-center gap-3"
|
||||
>
|
||||
<NavigationMenuItem
|
||||
v-for="(item, index) in mainNavItems"
|
||||
:key="index"
|
||||
class="relative flex h-full items-center"
|
||||
<AppLogo />
|
||||
</Link>
|
||||
</SheetHeader>
|
||||
|
||||
<div class="flex flex-col gap-5 p-4">
|
||||
<div class="relative">
|
||||
<Search
|
||||
class="text-on-surface-variant pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2"
|
||||
/>
|
||||
<input
|
||||
disabled
|
||||
aria-label="Search"
|
||||
placeholder="Coming soon"
|
||||
class="border-outline-variant bg-surface-container-low text-on-surface placeholder:text-on-surface-variant h-10 w-full rounded-lg border py-2 pl-9 pr-3 text-sm disabled:cursor-not-allowed disabled:opacity-100"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<nav class="flex flex-col gap-1" aria-label="Main">
|
||||
<Link
|
||||
v-for="item in mainNavItems"
|
||||
:key="item.title"
|
||||
:href="item.href"
|
||||
:class="navItemClasses(item)"
|
||||
>
|
||||
<Link
|
||||
:class="[
|
||||
navigationMenuTriggerStyle(),
|
||||
whenCurrentUrl(
|
||||
item.href,
|
||||
activeItemStyles,
|
||||
),
|
||||
'h-9 cursor-pointer px-3',
|
||||
]"
|
||||
:href="item.href"
|
||||
>
|
||||
<component
|
||||
v-if="item.icon"
|
||||
:is="item.icon"
|
||||
class="mr-2 h-4 w-4"
|
||||
/>
|
||||
{{ item.title }}
|
||||
</Link>
|
||||
<div
|
||||
v-if="isCurrentUrl(item.href)"
|
||||
class="absolute bottom-0 left-0 h-0.5 w-full translate-y-px bg-black dark:bg-white"
|
||||
></div>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
<component
|
||||
v-if="item.icon"
|
||||
:is="item.icon"
|
||||
class="size-4"
|
||||
/>
|
||||
{{ item.title }}
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
|
||||
<Link
|
||||
:href="dashboard()"
|
||||
class="flex shrink-0 items-center gap-2"
|
||||
aria-label="KanbanGit dashboard"
|
||||
>
|
||||
<AppLogo />
|
||||
</Link>
|
||||
|
||||
<nav
|
||||
class="ml-3 hidden min-w-0 flex-1 items-center gap-1 lg:flex"
|
||||
aria-label="Main"
|
||||
>
|
||||
<Link
|
||||
v-for="item in mainNavItems"
|
||||
:key="item.title"
|
||||
:href="item.href"
|
||||
:class="navItemClasses(item)"
|
||||
>
|
||||
<component
|
||||
v-if="item.icon"
|
||||
:is="item.icon"
|
||||
class="size-4"
|
||||
/>
|
||||
<span class="truncate">{{ item.title }}</span>
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
<div class="ml-auto flex items-center gap-3">
|
||||
<div class="relative hidden sm:block">
|
||||
<Search
|
||||
class="text-on-surface-variant pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2"
|
||||
/>
|
||||
<input
|
||||
disabled
|
||||
aria-label="Search"
|
||||
placeholder="Coming soon"
|
||||
class="border-outline-variant bg-surface-container-low text-on-surface placeholder:text-on-surface-variant h-10 w-48 rounded-lg border py-2 pl-9 pr-3 text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-100 md:w-64"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex items-center space-x-2">
|
||||
<div class="relative flex items-center space-x-1">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger :as-child="true">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="group h-9 w-9 cursor-pointer"
|
||||
class="focus-visible:ring-primary/30 hover:bg-surface-container-high size-10 rounded-full p-1 focus-visible:ring-2"
|
||||
>
|
||||
<Search
|
||||
class="size-5 opacity-80 group-hover:opacity-100"
|
||||
/>
|
||||
<UserAvatar rounded />
|
||||
<span class="sr-only">Open user menu</span>
|
||||
</Button>
|
||||
|
||||
<div class="hidden space-x-1 lg:flex">
|
||||
<template
|
||||
v-for="item in rightNavItems"
|
||||
:key="item.title"
|
||||
>
|
||||
<TooltipProvider :delay-duration="0">
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
as-child
|
||||
class="group h-9 w-9 cursor-pointer"
|
||||
>
|
||||
<a
|
||||
:href="toUrl(item.href)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<span class="sr-only">{{
|
||||
item.title
|
||||
}}</span>
|
||||
<component
|
||||
:is="item.icon"
|
||||
class="size-5 opacity-80 group-hover:opacity-100"
|
||||
/>
|
||||
</a>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{{ item.title }}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger :as-child="true">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="focus-within:ring-primary relative size-10 w-auto rounded-full p-1 focus-within:ring-2"
|
||||
>
|
||||
<UserAvatar rounded />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" class="w-56">
|
||||
<UserMenuContent :user="auth.user" />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
class="border-outline-variant bg-popover w-56"
|
||||
>
|
||||
<UserMenuContent :user="auth.user" />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="props.breadcrumbs.length > 1"
|
||||
class="border-sidebar-border/70 flex w-full border-b"
|
||||
class="border-outline-variant/70 bg-surface-container-low/70 border-t"
|
||||
>
|
||||
<div
|
||||
class="mx-auto flex h-12 w-full items-center justify-start px-4 text-neutral-500 md:max-w-7xl"
|
||||
class="text-on-surface-variant sm:px-container-margin flex h-11 w-full items-center px-4 text-sm"
|
||||
>
|
||||
<Breadcrumbs :breadcrumbs="breadcrumbs" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
@@ -4,13 +4,13 @@ import AppLogoIcon from '@/components/AppLogoIcon.vue';
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-md"
|
||||
class="bg-primary text-primary-foreground flex aspect-square size-9 items-center justify-center rounded-lg shadow-[0_8px_24px_rgba(0,110,47,0.18)]"
|
||||
>
|
||||
<AppLogoIcon class="size-5 fill-current text-white dark:text-black" />
|
||||
<AppLogoIcon class="size-5 fill-current" />
|
||||
</div>
|
||||
<div class="ml-1 grid flex-1 text-left text-sm">
|
||||
<span class="mb-0.5 truncate font-semibold leading-tight"
|
||||
>Laravel Starter Kit</span
|
||||
>
|
||||
<span class="text-primary truncate text-sm font-semibold leading-tight">
|
||||
KanbanGit
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -15,15 +15,15 @@ defineProps<Props>();
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 40 42"
|
||||
viewBox="0 0 32 32"
|
||||
:class="className"
|
||||
v-bind="$attrs"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M17.2 5.633 8.6.855 0 5.633v26.51l16.2 9 16.2-9v-8.442l7.6-4.223V9.856l-8.6-4.777-8.6 4.777V18.3l-5.6 3.111V5.633ZM38 18.301l-5.6 3.11v-6.157l5.6-3.11V18.3Zm-1.06-7.856-5.54 3.078-5.54-3.079 5.54-3.078 5.54 3.079ZM24.8 18.3v-6.157l5.6 3.111v6.158L24.8 18.3Zm-1 1.732 5.54 3.078-13.14 7.302-5.54-3.078 13.14-7.3v-.002Zm-16.2 7.89 7.6 4.222V38.3L2 30.966V7.92l5.6 3.111v16.892ZM8.6 9.3 3.06 6.222 8.6 3.143l5.54 3.08L8.6 9.3Zm21.8 15.51-13.2 7.334V38.3l13.2-7.334v-6.156ZM9.6 11.034l5.6-3.11v14.6l-5.6 3.11v-14.6Z"
|
||||
/>
|
||||
<rect x="4" y="5" width="7" height="22" rx="2" />
|
||||
<rect x="13" y="5" width="7" height="14" rx="2" opacity="0.82" />
|
||||
<rect x="22" y="5" width="6" height="18" rx="2" opacity="0.64" />
|
||||
<path d="M14 24h7v3h-7z" opacity="0.82" />
|
||||
<path d="M22 26h6v1h-6z" opacity="0.64" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
@@ -15,7 +15,10 @@ const isOpen = usePage().props.sidebarOpen;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="variant === 'header'" class="flex min-h-screen w-full flex-col">
|
||||
<div
|
||||
v-if="variant === 'header'"
|
||||
class="bg-background text-foreground flex min-h-screen w-full flex-col"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
<SidebarProvider v-else :default-open="isOpen">
|
||||
|
||||
@@ -76,12 +76,12 @@ const mainNavItems = computed<NavItem[]>(() => {
|
||||
const footerNavItems: NavItem[] = [
|
||||
{
|
||||
title: 'Repository',
|
||||
href: 'https://github.com/laravel/vue-starter-kit',
|
||||
href: 'https://git.twyco.de/OpenSource/KanbanGit',
|
||||
icon: FolderGit2,
|
||||
},
|
||||
{
|
||||
title: 'Documentation',
|
||||
href: 'https://laravel.com/docs/starter-kits#vue',
|
||||
href: 'https://git.twyco.de/OpenSource/KanbanGit/src/branch/main/README.md',
|
||||
icon: BookOpen,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import AppLayout from '@/layouts/app/AppSidebarLayout.vue';
|
||||
import AppLayout from '@/layouts/app/AppHeaderLayout.vue';
|
||||
import type { BreadcrumbItem } from '@/types';
|
||||
|
||||
type Props = {
|
||||
|
||||
Reference in New Issue
Block a user