fix: sidebar
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<header
|
||||
class="fixed top-0 left-0 right-0 z-50 bg-white/80 dark:bg-(--black) backdrop-blur-md border-b border-(--border-light) dark:border-(--border-dark)">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="px-4">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<RouterLink :to="{ name: 'home' }" class="flex items-center gap-2">
|
||||
<div class="w-8 h-8 rounded-lg bg-primary text-white flex items-center justify-center">
|
||||
@@ -15,6 +15,7 @@
|
||||
list: 'gap-4 text-(--black)',
|
||||
linkLabel: 'text-(--black) text-sm!'
|
||||
}" :items="menuItems" class="" />
|
||||
<!-- orientation="vertical" -->
|
||||
<div class="flex items-center gap-12">
|
||||
<div class="flex items-center gap-2">
|
||||
<CountryCurrencySwitch />
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
<template>
|
||||
<suspense>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="flex gap-10">
|
||||
<CategoryMenu />
|
||||
<div class="w-full flex flex-col items-center gap-4">
|
||||
<UTable :data="productsList" :columns="columns" class="flex-1 w-full" />
|
||||
<UPagination v-model:page="page" :total="total" :items-per-page="perPage" />
|
||||
</div>
|
||||
</div>
|
||||
</component>
|
||||
</suspense>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="flex gap-10">
|
||||
<CategoryMenu />
|
||||
<div class="w-full flex flex-col items-center gap-4">
|
||||
<UTable :data="productsList" :columns="columns" class="flex-1 w-full" />
|
||||
<UPagination v-model:page="page" :total="total" :items-per-page="perPage" />
|
||||
</div>
|
||||
</div>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -154,6 +152,12 @@ async function fetchProductList() {
|
||||
}
|
||||
|
||||
function goToProduct(productId: number) {
|
||||
let path = {
|
||||
name: route.name,
|
||||
params: route.params,
|
||||
query: route.query
|
||||
}
|
||||
localStorage.setItem('back_from_product', JSON.stringify(path))
|
||||
router.push({
|
||||
name: 'customer-product-details',
|
||||
params: { product_id: productId }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<component :is="Default || 'div'">
|
||||
|
||||
<p class="cursor-pointer" @click="backFromProduct()">Back to products</p>
|
||||
<div class="container my-10 mx-auto ">
|
||||
<div
|
||||
class="flex items-end justify-between gap-4 mb-6 bg-(--second-light) dark:bg-(--main-dark) border border-(--border-light) dark:border-(--border-dark) p-4 rounded-md">
|
||||
@@ -141,7 +141,28 @@ import type { Language } from '@/types';
|
||||
import { watch } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
const router = useRouter()
|
||||
function backFromProduct() {
|
||||
let path = localStorage.getItem('back_from_product')
|
||||
|
||||
if (path) {
|
||||
let res = JSON.parse(path)
|
||||
router.push({
|
||||
name: res.name,
|
||||
params: res.params,
|
||||
query: res.query
|
||||
})
|
||||
|
||||
localStorage.removeItem('back_from_product')
|
||||
} else {
|
||||
router.push({
|
||||
name: 'customer-products',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const route = useRoute()
|
||||
const settingStore = useSettingsStore()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="container mx-auto">
|
||||
<div class="">
|
||||
<h2
|
||||
class="font-semibold text-black dark:text-white pb-6 text-2xl">
|
||||
{{ t('Cart Items') }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="container mx-auto">
|
||||
<div class="">
|
||||
<div class="flex flex-col gap-5 mb-6">
|
||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Addresses') }}</h1>
|
||||
<div class="flex md:flex-row flex-col justify-between items-start md:items-center gap-5 md:gap-0">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="container mx-auto flex flex-col gap-5 md:gap-10">
|
||||
<div class="flex flex-col gap-5 md:gap-10">
|
||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Shopping Cart') }}</h1>
|
||||
<div class="flex flex-col lg:flex-row gap-5 md:gap-10">
|
||||
<div class="flex-1">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="container mx-auto">
|
||||
<div class="">
|
||||
<div class="flex md:flex-row flex-col justify-between gap-8 my-6">
|
||||
<div class="flex-1">
|
||||
<div class="bg-gray-100 dark:bg-gray-800 rounded-lg p-8 flex items-center justify-center min-h-[300px] ">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<suspense>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="container mx-auto">
|
||||
<div class="">
|
||||
<!-- <UNavigationMenu orientation="vertical" :items="listing" class="data-[orientation=vertical]:w-48">
|
||||
<template #item="{ item, active }">
|
||||
<div class="flex items-center gap-2 px-3 py-2">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="container mx-auto">
|
||||
<div class="">
|
||||
<div class="flex flex-col gap-5 mb-6">
|
||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Customer Data') }}</h1>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="container mx-auto">
|
||||
<div class="">
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<div class="flex flex-col gap-5 mb-6">
|
||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Create Account') }}</h1>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
<!-- <script setup lang="ts">
|
||||
import TopBar from '@/components/TopBar.vue';
|
||||
</script>
|
||||
|
||||
@@ -6,9 +6,289 @@ import TopBar from '@/components/TopBar.vue';
|
||||
<div class="h-screen grid grid-rows-[auto_1fr_auto]">
|
||||
<main class="pt-20 pb-10">
|
||||
<TopBar />
|
||||
<div class="container mx-auto px-4">
|
||||
<div class=" px-4">
|
||||
<slot />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template> -->
|
||||
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useColorMode } from '@vueuse/core'
|
||||
import type { DropdownMenuItem, NavigationMenuItem } from '@nuxt/ui'
|
||||
import { defineShortcuts, extractShortcuts } from '@nuxt/ui/runtime/composables/defineShortcuts.js'
|
||||
import { LabelTrans, TopMenuItem } from '@/types'
|
||||
|
||||
const open = ref(true)
|
||||
|
||||
const colorMode = useColorMode()
|
||||
|
||||
const teams = ref([
|
||||
{
|
||||
label: 'Nuxt',
|
||||
avatar: {
|
||||
src: 'https://github.com/nuxt.png',
|
||||
alt: 'Nuxt'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Vue',
|
||||
avatar: {
|
||||
src: 'https://github.com/vuejs.png',
|
||||
alt: 'Vue'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'UnJS',
|
||||
avatar: {
|
||||
src: 'https://github.com/unjs.png',
|
||||
alt: 'UnJS'
|
||||
}
|
||||
}
|
||||
])
|
||||
const selectedTeam = ref(teams.value[0])
|
||||
|
||||
const teamsItems = computed<DropdownMenuItem[][]>(() => {
|
||||
return [
|
||||
teams.value.map((team, index) => ({
|
||||
...team,
|
||||
kbds: ['meta', String(index + 1)],
|
||||
onSelect() {
|
||||
selectedTeam.value = team
|
||||
}
|
||||
})),
|
||||
[
|
||||
{
|
||||
label: 'Create team',
|
||||
icon: 'i-lucide-circle-plus'
|
||||
}
|
||||
]
|
||||
]
|
||||
})
|
||||
|
||||
function getItems(state: 'collapsed' | 'expanded') {
|
||||
return [
|
||||
{
|
||||
label: 'Inbox',
|
||||
icon: 'i-lucide-inbox',
|
||||
badge: '4'
|
||||
},
|
||||
{
|
||||
label: 'Issues',
|
||||
icon: 'i-lucide-square-dot'
|
||||
},
|
||||
{
|
||||
label: 'Activity',
|
||||
icon: 'i-lucide-square-activity'
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-settings',
|
||||
defaultOpen: true,
|
||||
children:
|
||||
state === 'expanded'
|
||||
? [
|
||||
{
|
||||
label: 'General',
|
||||
icon: 'i-lucide-house'
|
||||
},
|
||||
{
|
||||
label: 'Team',
|
||||
icon: 'i-lucide-users'
|
||||
},
|
||||
{
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}
|
||||
]
|
||||
: []
|
||||
}
|
||||
] satisfies NavigationMenuItem[]
|
||||
}
|
||||
|
||||
// zsdasdad
|
||||
import { useRouter } from 'vue-router'
|
||||
import { currentLang } from '@/router/langs'
|
||||
import { useFetchJson } from '@/composable/useFetchJson'
|
||||
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const menu = ref<TopMenuItem[] | null>(null)
|
||||
|
||||
async function getTopMenu() {
|
||||
try {
|
||||
const { items } = await useFetchJson<TopMenuItem[]>('/api/v1/restricted/menu/get-top-menu')
|
||||
menu.value = items
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getTopMenu()
|
||||
})
|
||||
|
||||
const menuItems = computed(() => {
|
||||
if (!menu.value?.length) return []
|
||||
|
||||
return transformMenu(
|
||||
menu.value[0]?.children || [],
|
||||
currentLang.value?.iso_code
|
||||
)
|
||||
})
|
||||
|
||||
function transformMenu(
|
||||
items: TopMenuItem[],
|
||||
locale: string | undefined
|
||||
): NavigationMenuItem[] {
|
||||
return items.map((item) => {
|
||||
const route: NavigationMenuItem = {
|
||||
icon: item.label.icon || 'i-lucide-house',
|
||||
label:
|
||||
item.label.trans?.[locale as keyof LabelTrans]?.label ||
|
||||
item.label.trans?.en?.label ||
|
||||
'—',
|
||||
children: item.children
|
||||
? transformMenu(item.children, locale)
|
||||
: undefined,
|
||||
onSelect: () => {
|
||||
router.push({
|
||||
name: item.params.route.name,
|
||||
params: {
|
||||
...(item.params.route.params || {}),
|
||||
locale: currentLang.value?.iso_code
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return route
|
||||
})
|
||||
}
|
||||
|
||||
const user = ref({
|
||||
name: 'Benjamin Canac',
|
||||
avatar: {
|
||||
src: 'https://github.com/benjamincanac.png',
|
||||
alt: 'Benjamin Canac'
|
||||
}
|
||||
})
|
||||
|
||||
const userItems = computed<DropdownMenuItem[][]>(() => [
|
||||
[
|
||||
{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user'
|
||||
},
|
||||
{
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-settings',
|
||||
to: '/settings'
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Appearance',
|
||||
icon: 'i-lucide-sun-moon',
|
||||
children: [
|
||||
{
|
||||
label: 'Light',
|
||||
icon: 'i-lucide-sun',
|
||||
type: 'checkbox',
|
||||
checked: colorMode.value === 'light',
|
||||
onUpdateChecked(checked: boolean) {
|
||||
if (checked) {
|
||||
colorMode.preference = 'light'
|
||||
}
|
||||
},
|
||||
onSelect(e: Event) {
|
||||
e.preventDefault()
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Dark',
|
||||
icon: 'i-lucide-moon',
|
||||
type: 'checkbox',
|
||||
checked: colorMode.value === 'dark',
|
||||
onUpdateChecked(checked: boolean) {
|
||||
if (checked) {
|
||||
colorMode.preference = 'dark'
|
||||
}
|
||||
},
|
||||
onSelect(e: Event) {
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'GitHub',
|
||||
icon: 'i-simple-icons-github',
|
||||
to: 'https://github.com/nuxt/ui',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Log out',
|
||||
icon: 'i-lucide-log-out'
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
defineShortcuts(extractShortcuts(teamsItems.value))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-1">
|
||||
<USidebar v-model:open="open" collapsible="icon" rail :ui="{
|
||||
container: 'h-full',
|
||||
inner: 'bg-elevated/25 divide-transparent',
|
||||
body: 'py-0'
|
||||
}">
|
||||
<template #header>
|
||||
<UDropdownMenu :items="teamsItems" :content="{ align: 'start', collisionPadding: 12 }"
|
||||
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-48' }">
|
||||
<UButton v-bind="selectedTeam" trailing-icon="i-lucide-chevrons-up-down" color="neutral" variant="ghost"
|
||||
square class="w-full data-[state=open]:bg-elevated overflow-hidden" :ui="{
|
||||
trailingIcon: 'text-dimmed ms-auto'
|
||||
}" />
|
||||
</UDropdownMenu>
|
||||
</template>
|
||||
|
||||
<template #default="{ state }">
|
||||
<UNavigationMenu :key="state" :items="menuItems" orientation="vertical"
|
||||
:ui="{ link: 'p-1.5 overflow-hidden' }" />
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<UDropdownMenu :items="userItems" :content="{ align: 'center', collisionPadding: 12 }"
|
||||
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-48' }">
|
||||
<UButton v-bind="user" :label="user?.name" trailing-icon="i-lucide-chevrons-up-down" color="neutral"
|
||||
variant="ghost" square class="w-full data-[state=open]:bg-elevated overflow-hidden" :ui="{
|
||||
trailingIcon: 'text-dimmed ms-auto'
|
||||
}" />
|
||||
</UDropdownMenu>
|
||||
</template>
|
||||
</USidebar>
|
||||
|
||||
<div class="flex-1 flex flex-col">
|
||||
<div class="h-(--ui-header-height) shrink-0 flex items-center px-4 border-b border-default">
|
||||
<UButton icon="i-lucide-panel-left" color="neutral" variant="ghost" aria-label="Toggle sidebar"
|
||||
@click="open = !open" />
|
||||
</div>
|
||||
|
||||
<div class="flex-1 p-4">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { currentLang, langs } from './langs'
|
||||
import { currentLang, langs, switchLocalization } from './langs'
|
||||
import { getSettings } from './settings'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { getRoutes } from './menu'
|
||||
@@ -8,6 +8,7 @@ function isAuthenticated(): boolean {
|
||||
if (typeof document === 'undefined') return false
|
||||
return document.cookie.split('; ').some((c) => c === 'is_authenticated=1')
|
||||
}
|
||||
await switchLocalization()
|
||||
await getSettings()
|
||||
|
||||
const routes = await getRoutes()
|
||||
|
||||
@@ -183,7 +183,7 @@ const columns = computed<TableColumn<IssueTimeSummary>[]>(() => [
|
||||
|
||||
<template>
|
||||
<component :is="Default || 'div'">
|
||||
<div class="container mx-auto">
|
||||
<div class="">
|
||||
<div class="p-6 bg-(--main-light) dark:bg-(--black) font-sans">
|
||||
<h1 class="text-2xl font-bold mb-6 text-black dark:text-white">{{ $t('repo_chart.repository_work_chart') }}
|
||||
</h1>
|
||||
|
||||
Reference in New Issue
Block a user