Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ Inspiration, code snippets, icon, etc.
- [Template Typescript](https://github.com/foxglove/template-typescript) by Foxglove.
- [`shadcn` Vue](https://www.shadcn-vue.com/)
- [`shadcn` UI Sidebar](https://github1s.com/salimi-my/shadcn-ui-sidebar) by Salimi
- [Iconify](https://iconify.design/) by Vjacheslav Trushkin
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
"component:add": "npx shadcn-vue@latest add"
},
"devDependencies": {
"@iconify-json/lucide": "^1.1.198",
"@iconify-json/radix-icons": "^1.1.14",
"@iconify/vue": "^4.1.2",
"@playwright/test": "^1.42.1",
"@rushstack/eslint-patch": "^1.10.1",
"@types/jsdom": "^21.1.6",
Expand All @@ -42,9 +45,9 @@
"@vue/tsconfig": "^0.5.1",
"@vueuse/core": "^10.11.0",
"autoprefixer": "^10.4.19",
"cross-env": "^7.0.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-playwright": "^1.5.4",
Expand All @@ -53,7 +56,6 @@
"husky": "^9.0.11",
"jsdom": "^24.0.0",
"lint-staged": "^15.2.2",
"lucide-vue-next": "^0.398.0",
"npm-run-all2": "^6.1.2",
"postcss": "^8.4.38",
"postcss-import": "^16.1.0",
Expand Down
30 changes: 24 additions & 6 deletions public/data/sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
{
"groupLabel": "",
"menus": [
{ "href": "/", "label": "Dashboard", "active": true, "icon": "LayoutGrid", "submenus": [] }
{
"href": "/",
"label": "Dashboard",
"active": true,
"icon": "lucide:layout-grid",
"submenus": []
}
]
},
{
Expand All @@ -12,21 +18,33 @@
"href": "",
"label": "Posts",
"active": false,
"icon": "SquarePen",
"icon": "lucide:square-pen",
"submenus": [
{ "href": "/", "label": "All Posts", "active": false },
{ "href": "/", "label": "New Post", "active": false }
]
},
{ "href": "/", "label": "Categories", "active": false, "icon": "Bookmark", "submenus": [] },
{ "href": "/", "label": "Tags", "active": false, "icon": "Tag", "submenus": [] }
{
"href": "/",
"label": "Categories",
"active": false,
"icon": "lucide:bookmark",
"submenus": []
},
{ "href": "/", "label": "Tags", "active": false, "icon": "lucide:tag", "submenus": [] }
]
},
{
"groupLabel": "Settings",
"menus": [
{ "href": "/", "label": "Users", "active": false, "icon": "Users", "submenus": [] },
{ "href": "/", "label": "Account", "active": false, "icon": "Settings", "submenus": [] }
{ "href": "/", "label": "Users", "active": false, "icon": "lucide:users", "submenus": [] },
{
"href": "/",
"label": "Account",
"active": false,
"icon": "lucide:settings",
"submenus": []
}
]
}
]
2 changes: 1 addition & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useGlobalStore } from "@/stores/use-global";
const globalStore = useGlobalStore();
onMounted(function () {
globalStore.loadLocale();
globalStore.loadTheme();
globalStore.loadDarkMode();
});
</script>

Expand Down
7 changes: 3 additions & 4 deletions src/components/LoginForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { cn } from "@/utils/classname";
import { ref } from "vue";
import { Loader2 } from "lucide-vue-next";

const isLoading = ref(false);
async function onSubmit(event: Event) {
Expand Down Expand Up @@ -58,7 +57,7 @@ async function onSubmit(event: Event) {
</div>
</div>
<Button variant="outline" type="button" class="justify-start" :disabled="isLoading">
<Loader2 v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
<Icon icon="lucide:loader-circle" v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
<img
v-else
src="https://cdn.worldvectorlogo.com/logos/github-icon-1.svg"
Expand All @@ -67,7 +66,7 @@ async function onSubmit(event: Event) {
Continue with GitHub
</Button>
<Button variant="outline" type="button" class="justify-start" :disabled="isLoading">
<Loader2 v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
<Icon icon="lucide:loader-circle" v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
<img
v-else
src="https://www.svgrepo.com/show/303108/google-icon-logo.svg"
Expand All @@ -76,7 +75,7 @@ async function onSubmit(event: Event) {
Continue with Google
</Button>
<Button variant="outline" type="button" class="justify-start" :disabled="isLoading">
<Loader2 v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
<Icon icon="lucide:loader-circle" v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
<img
v-else
src="https://cdn.worldvectorlogo.com/logos/microsoft-5.svg"
Expand Down
5 changes: 2 additions & 3 deletions src/components/RegisterForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { cn } from "@/utils/classname";
import { ref } from "vue";

import { Loader2, Github } from "lucide-vue-next";
import { Label } from "@/components/ui/label";
import { Icon } from "@iconify/vue";

const isLoading = ref(false);
async function onSubmit(event: Event) {
Expand Down Expand Up @@ -36,7 +35,7 @@ async function onSubmit(event: Event) {
/>
</div>
<Button :disabled="isLoading">
<Loader2 v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
<Icon icon="lucide:loader-circle" v-if="isLoading" class="mr-2 h-4 w-4 animate-spin" />
Register with Email
</Button>
</div>
Expand Down
36 changes: 36 additions & 0 deletions src/components/ui/dark-mode/DarkModeToggle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import { useColorMode } from "@vueuse/core";
import { Icon } from "@iconify/vue";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

const mode = useColorMode();
</script>

<template>
<DropdownMenu>
<DropdownMenuTrigger as-child>
<Button variant="outline">
<Icon
icon="radix-icons:moon"
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
/>
<Icon
icon="radix-icons:sun"
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
/>
<span class="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem @click="mode = 'light'"> Light </DropdownMenuItem>
<DropdownMenuItem @click="mode = 'dark'"> Dark </DropdownMenuItem>
<DropdownMenuItem @click="mode = 'auto'"> System </DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</template>
1 change: 1 addition & 0 deletions src/components/ui/dark-mode/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as DarkModeToggle } from "./DarkModeToggle.vue";
32 changes: 17 additions & 15 deletions src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { type HTMLAttributes, computed } from "vue";
import {
DropdownMenuCheckboxItem,
type DropdownMenuCheckboxItemEmits,
type DropdownMenuCheckboxItemProps,
DropdownMenuItemIndicator,
useForwardPropsEmits,
} from 'radix-vue'
import { Check } from 'lucide-vue-next'
import { cn } from '@/utils/classname'
} from "radix-vue";
import { cn } from "@/utils/classname";
import { Icon } from "@iconify/vue";

const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DropdownMenuCheckboxItemEmits>()
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes["class"] }>();
const emits = defineEmits<DropdownMenuCheckboxItemEmits>();

const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;

return delegated
})
return delegated;
});

const forwarded = useForwardPropsEmits(delegatedProps, emits)
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>

<template>
<DropdownMenuCheckboxItem
v-bind="forwarded"
:class=" cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
props.class,
)"
:class="
cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
props.class,
)
"
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Check class="w-4 h-4" />
<Icon icon="lucide:check" class="w-4 h-4" />
</DropdownMenuItemIndicator>
</span>
<slot />
Expand Down
32 changes: 17 additions & 15 deletions src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue
Original file line number Diff line number Diff line change
@@ -1,39 +1,41 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { type HTMLAttributes, computed } from "vue";
import {
DropdownMenuItemIndicator,
DropdownMenuRadioItem,
type DropdownMenuRadioItemEmits,
type DropdownMenuRadioItemProps,
useForwardPropsEmits,
} from 'radix-vue'
import { Circle } from 'lucide-vue-next'
import { cn } from '@/utils/classname'
} from "radix-vue";
import { cn } from "@/utils/classname";
import { Icon } from "@iconify/vue";

const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes['class'] }>()
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes["class"] }>();

const emits = defineEmits<DropdownMenuRadioItemEmits>()
const emits = defineEmits<DropdownMenuRadioItemEmits>();

const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;

return delegated
})
return delegated;
});

const forwarded = useForwardPropsEmits(delegatedProps, emits)
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>

<template>
<DropdownMenuRadioItem
v-bind="forwarded"
:class="cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
props.class,
)"
:class="
cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
props.class,
)
"
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Circle class="h-2 w-2 fill-current" />
<Icon icon="lucide:circle" class="h-2 w-2 fill-current" />
</DropdownMenuItemIndicator>
</span>
<slot />
Expand Down
30 changes: 16 additions & 14 deletions src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue'
import { type HTMLAttributes, computed } from "vue";
import {
DropdownMenuSubTrigger,
type DropdownMenuSubTriggerProps,
useForwardProps,
} from 'radix-vue'
import { ChevronRight } from 'lucide-vue-next'
import { cn } from '@/utils/classname'
} from "radix-vue";
import { cn } from "@/utils/classname";
import { Icon } from "@iconify/vue";

const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes['class'] }>()
const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes["class"] }>();

const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;

return delegated
})
return delegated;
});

const forwardedProps = useForwardProps(delegatedProps)
const forwardedProps = useForwardProps(delegatedProps);
</script>

<template>
<DropdownMenuSubTrigger
v-bind="forwardedProps"
:class="cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
props.class,
)"
:class="
cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
props.class,
)
"
>
<slot />
<ChevronRight class="ml-auto h-4 w-4" />
<Icon icon="lucide:chevron-right" class="ml-auto h-4 w-4" />
</DropdownMenuSubTrigger>
</template>
10 changes: 5 additions & 5 deletions src/components/ui/navbar/Navbar.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script setup lang="ts">
import { Menu, PanelsTopLeft } from "lucide-vue-next";
import { Button } from "@/components/ui/button";
import { DarkModeToggle } from "@/components/ui/dark-mode";
import { Sheet, SheetContent, SheetHeader, SheetTrigger } from "@/components/ui/sheet";
import { default as SidebarMenu } from "@/components/ui/sidebar/SidebarMenu.vue";
import { Icon } from "@iconify/vue";

interface NavbarProps {
title: string;
Expand All @@ -20,14 +21,14 @@ const props = defineProps<NavbarProps>();
<Sheet>
<SheetTrigger class="lg:hidden" as-child>
<Button variant="outline" class="mr-3 p-3 lg:hidden">
<Menu class="w-5" />
<Icon icon="lucide:menu" class="w-5" />
</Button>
</SheetTrigger>
<SheetContent class="sm:w-80 px-3 h-full flex flex-col" side="left">
<SheetHeader>
<Button class="flex justify-center items-center pb-2 pt-1" variant="link" as-child>
<RouterLink to="/" class="flex items-center gap-2">
<PanelsTopLeft class="w-6 h-6 mr-1" />
<Icon icon="lucide:panels-top-left" class="w-6 h-6 mr-1" />
<h1 class="font-bold text-lg">Brand</h1>
</RouterLink>
</Button>
Expand All @@ -39,8 +40,7 @@ const props = defineProps<NavbarProps>();
<h1 class="font-bold">{{ props.title }}</h1>
</div>
<div class="flex flex-1 items-center space-x-2 justify-end">
<!-- <ModeToggle />
<UserNav /> -->
<DarkModeToggle />
</div>
</div>
</header>
Expand Down
Loading