Dev branch
This commit is contained in:
@@ -23,6 +23,9 @@ import DropdownLink from "@/Components/DropdownLink.vue";
|
||||
import GlobalSearch from "@/Layouts/Partials/GlobalSearch.vue";
|
||||
import NotificationsBell from "@/Layouts/Partials/NotificationsBell.vue";
|
||||
import ApplicationMark from "@/Components/ApplicationMark.vue";
|
||||
import Breadcrumbs from "@/Components/Breadcrumbs.vue";
|
||||
import ToastContainer from "@/Components/Toast/ToastContainer.vue";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
|
||||
const props = defineProps({ title: { type: String, default: "Administrator" } });
|
||||
|
||||
@@ -205,47 +208,69 @@ function isActive(patterns) {
|
||||
<aside
|
||||
:class="[
|
||||
sidebarCollapsed ? 'w-16' : 'w-60',
|
||||
'bg-white border-r border-gray-200 transition-all duration-200 z-50',
|
||||
'bg-white border-r border-gray-200 transition-all duration-300 ease-in-out z-50',
|
||||
isMobile
|
||||
? 'fixed inset-y-0 left-0 transform ' +
|
||||
? 'fixed inset-y-0 left-0 transform shadow-strong ' +
|
||||
(mobileSidebarOpen ? 'translate-x-0' : '-translate-x-full')
|
||||
: 'sticky top-0 h-screen',
|
||||
: 'sticky top-0 h-screen overflow-y-auto',
|
||||
]"
|
||||
>
|
||||
<div class="h-16 px-4 flex items-center justify-between border-b">
|
||||
<Link :href="route('dashboard')" class="flex items-center gap-2">
|
||||
<ApplicationMark class="h-8 w-auto" />
|
||||
<span v-if="!sidebarCollapsed" class="text-sm font-semibold">Admin</span>
|
||||
<div class="h-16 px-4 flex items-center justify-between border-b border-gray-200 bg-white">
|
||||
<Link
|
||||
:href="route('dashboard')"
|
||||
class="flex items-center gap-2 hover:opacity-80 transition-opacity"
|
||||
>
|
||||
<ApplicationMark />
|
||||
<span
|
||||
v-if="!sidebarCollapsed"
|
||||
class="text-sm font-semibold text-gray-900 transition-opacity"
|
||||
>
|
||||
Admin
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
<nav class="py-4 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-200">
|
||||
<div v-for="group in navGroups" :key="group.key" class="mt-2 first:mt-0">
|
||||
<nav class="py-4 overflow-y-auto">
|
||||
<div v-for="group in navGroups" :key="group.key" class="mt-2 first:mt-0 px-2">
|
||||
<p
|
||||
v-if="!sidebarCollapsed"
|
||||
class="px-4 mb-1 mt-4 first:mt-0 text-[10px] font-semibold uppercase tracking-wider text-gray-400"
|
||||
class="px-4 py-1.5 mb-1 mt-4 first:mt-0 text-[11px] font-semibold uppercase tracking-wider text-gray-400"
|
||||
>
|
||||
{{ group.label }}
|
||||
</p>
|
||||
<ul class="space-y-1">
|
||||
<ul class="space-y-0.5">
|
||||
<li v-for="item in group.items" :key="item.key">
|
||||
<Link
|
||||
:href="route(item.route)"
|
||||
:title="item.label"
|
||||
:class="[
|
||||
'flex items-center gap-3 px-4 py-2 text-sm hover:bg-gray-100',
|
||||
isActive(item.active) ? 'bg-gray-100 text-gray-900' : 'text-gray-600',
|
||||
'flex items-center gap-3 px-3 py-2.5 text-sm rounded-lg transition-all duration-150',
|
||||
isActive(item.active)
|
||||
? 'bg-primary-50 text-primary-700 font-medium shadow-sm'
|
||||
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900',
|
||||
]"
|
||||
>
|
||||
<FontAwesomeIcon :icon="item.icon" class="w-5 h-5 text-gray-600" />
|
||||
<span v-if="!sidebarCollapsed">{{ item.label }}</span>
|
||||
<FontAwesomeIcon
|
||||
:icon="item.icon"
|
||||
:class="[
|
||||
'w-5 h-5 flex-shrink-0 transition-colors',
|
||||
isActive(item.active) ? 'text-primary-600' : 'text-gray-500',
|
||||
]"
|
||||
/>
|
||||
<span
|
||||
v-if="!sidebarCollapsed"
|
||||
class="truncate transition-opacity"
|
||||
:class="{ 'font-medium': isActive(item.active) }"
|
||||
>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mt-6 border-t pt-4 space-y-2 px-4">
|
||||
<div class="mt-6 border-t border-gray-200 pt-4 space-y-2 px-4">
|
||||
<Link
|
||||
:href="route('dashboard')"
|
||||
class="text-xs text-gray-500 hover:underline flex items-center gap-1"
|
||||
class="text-xs text-gray-500 hover:text-gray-700 hover:underline flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
<FontAwesomeIcon :icon="faArrowLeft" class="w-3.5 h-3.5" />
|
||||
<span v-if="!sidebarCollapsed">Nazaj na aplikacijo</span>
|
||||
@@ -256,18 +281,18 @@ function isActive(patterns) {
|
||||
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<div
|
||||
class="h-16 bg-white border-b border-gray-100 px-4 flex items-center justify-between sticky top-0 z-30"
|
||||
class="h-16 bg-white border-b border-gray-200 px-4 flex items-center justify-between sticky top-0 z-30 backdrop-blur-sm bg-white/95 shadow-sm"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
<div class="flex items-center gap-3">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@click="toggleSidebar"
|
||||
class="inline-flex items-center justify-center w-9 h-9 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100"
|
||||
aria-label="Toggle sidebar"
|
||||
>
|
||||
<!-- Replaced raw SVG with FontAwesome icon -->
|
||||
<FontAwesomeIcon :icon="faBars" class="w-5 h-5" />
|
||||
</button>
|
||||
<h1 class="text-base font-semibold text-gray-800 hidden sm:block">
|
||||
</Button>
|
||||
<h1 class="text-base font-semibold text-gray-900 hidden sm:block">
|
||||
{{ title }}
|
||||
</h1>
|
||||
</div>
|
||||
@@ -279,23 +304,25 @@ function isActive(patterns) {
|
||||
<template #trigger>
|
||||
<button
|
||||
v-if="$page.props.jetstream?.managesProfilePhotos"
|
||||
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-gray-300 transition"
|
||||
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-primary-500 focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 transition-all hover:ring-2 hover:ring-gray-200"
|
||||
>
|
||||
<img
|
||||
class="h-8 w-8 rounded-full object-cover"
|
||||
class="h-8 w-8 rounded-full object-cover ring-2 ring-gray-100"
|
||||
:src="$page.props.auth.user.profile_photo_url"
|
||||
:alt="$page.props.auth.user.name"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<span v-else class="inline-flex rounded-md">
|
||||
<button
|
||||
<span v-else class="inline-flex">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="default"
|
||||
type="button"
|
||||
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none focus:bg-gray-50 active:bg-gray-50 transition ease-in-out duration-150"
|
||||
class="gap-2"
|
||||
>
|
||||
{{ $page.props.auth.user.name }}
|
||||
<svg
|
||||
class="ms-2 -me-0.5 h-4 w-4"
|
||||
class="h-4 w-4"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -308,7 +335,7 @@ function isActive(patterns) {
|
||||
d="M19.5 8.25l-7.5 7.5-7.5-7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@@ -330,25 +357,29 @@ function isActive(patterns) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="p-4">
|
||||
<div
|
||||
v-if="$page.props.flash?.success"
|
||||
class="mb-4 rounded bg-emerald-50 border border-emerald-200 text-emerald-700 px-4 py-2 text-sm"
|
||||
>
|
||||
{{ $page.props.flash.success }}
|
||||
</div>
|
||||
<div
|
||||
v-if="$page.props.errors && Object.keys($page.props.errors).length"
|
||||
class="mb-4 rounded bg-rose-50 border border-rose-200 text-rose-700 px-4 py-2 text-sm"
|
||||
>
|
||||
<ul class="list-disc ml-5 space-y-1">
|
||||
<li v-for="(err, key) in $page.props.errors" :key="key">{{ err }}</li>
|
||||
</ul>
|
||||
<!-- Page Heading -->
|
||||
<header
|
||||
v-if="$slots.header"
|
||||
class="bg-white border-b border-gray-200 shadow-sm"
|
||||
>
|
||||
<div class="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8 space-y-2">
|
||||
<Breadcrumbs
|
||||
v-if="$page.props.breadcrumbs && $page.props.breadcrumbs.length"
|
||||
:breadcrumbs="$page.props.breadcrumbs"
|
||||
/>
|
||||
<slot name="header" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="flex-1 p-4 sm:p-6">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<GlobalSearch :open="false" />
|
||||
|
||||
<!-- Toast Notification Container -->
|
||||
<ToastContainer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import DropdownLink from "@/Components/DropdownLink.vue";
|
||||
import Breadcrumbs from "@/Components/Breadcrumbs.vue";
|
||||
import GlobalSearch from "./Partials/GlobalSearch.vue";
|
||||
import NotificationsBell from "./Partials/NotificationsBell.vue";
|
||||
import ToastContainer from "@/Components/Toast/ToastContainer.vue";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import {
|
||||
faMobileScreenButton,
|
||||
@@ -102,25 +104,7 @@ const logout = () => {
|
||||
|
||||
// Flash toast notifications
|
||||
const page = usePage();
|
||||
const flash = computed(() => page.props.flash || {});
|
||||
const showToast = ref(false);
|
||||
const toastMessage = ref("");
|
||||
const toastType = ref("success");
|
||||
watch(
|
||||
() => [flash.value.success, flash.value.error, flash.value.warning, flash.value.info],
|
||||
([s, e, w, i]) => {
|
||||
const message = s || e || w || i;
|
||||
const type = s ? "success" : e ? "error" : w ? "warning" : i ? "info" : null;
|
||||
if (message && type) {
|
||||
toastMessage.value = message;
|
||||
toastType.value = type;
|
||||
showToast.value = true;
|
||||
// auto-hide after 3s
|
||||
setTimeout(() => (showToast.value = false), 3000);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
// Toast notifications are now handled by ToastContainer component
|
||||
|
||||
// No automatic daily notifications
|
||||
|
||||
@@ -135,6 +119,13 @@ const rawMenuGroups = [
|
||||
routeName: "dashboard",
|
||||
active: ["dashboard"],
|
||||
},
|
||||
{
|
||||
key: "reports",
|
||||
title: "Poročila",
|
||||
routeName: "reports.index",
|
||||
active: ["reports.index", "reports.show"],
|
||||
requires: { permission: "reports-view" },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -268,6 +259,7 @@ const menuIconMap = {
|
||||
fieldjobs: faMap,
|
||||
settings: faGear,
|
||||
"admin-panel": faUserGroup,
|
||||
reports: faTableList,
|
||||
};
|
||||
|
||||
function isActive(patterns) {
|
||||
@@ -297,38 +289,46 @@ function isActive(patterns) {
|
||||
<aside
|
||||
:class="[
|
||||
sidebarCollapsed ? 'w-16' : 'w-64',
|
||||
'bg-white border-r border-gray-200 transition-all duration-200 z-50',
|
||||
'bg-white border-r border-gray-200 transition-all duration-300 ease-in-out z-50',
|
||||
// Off-canvas behavior on mobile; sticky fixed-like sidebar on desktop
|
||||
isMobile
|
||||
? 'fixed inset-y-0 left-0 transform ' +
|
||||
? 'fixed inset-y-0 left-0 transform shadow-strong ' +
|
||||
(mobileSidebarOpen ? 'translate-x-0' : '-translate-x-full')
|
||||
: 'sticky top-0 h-screen overflow-y-auto',
|
||||
]"
|
||||
>
|
||||
<div class="h-16 px-4 flex items-center justify-between border-b">
|
||||
<Link :href="route('dashboard')" class="flex items-center gap-2">
|
||||
<ApplicationMark class="h-8 w-auto" />
|
||||
<span v-if="!sidebarCollapsed" class="text-sm font-semibold">Teren</span>
|
||||
<div class="h-16 px-4 flex items-center justify-between border-b border-gray-200 bg-white">
|
||||
<Link
|
||||
:href="route('dashboard')"
|
||||
class="flex items-center gap-2 hover:opacity-80 transition-opacity"
|
||||
>
|
||||
<ApplicationMark />
|
||||
<span
|
||||
v-if="!sidebarCollapsed"
|
||||
class="text-sm font-semibold text-gray-900 transition-opacity"
|
||||
>
|
||||
Teren
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
<nav class="py-4">
|
||||
<ul class="space-y-3">
|
||||
<nav class="py-4 overflow-y-auto">
|
||||
<ul class="space-y-4 px-2">
|
||||
<li v-for="group in menuGroups" :key="group.label">
|
||||
<div
|
||||
v-if="!sidebarCollapsed"
|
||||
class="px-4 py-1 text-[11px] uppercase tracking-wide text-gray-400"
|
||||
class="px-4 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-gray-400"
|
||||
>
|
||||
{{ group.label }}
|
||||
</div>
|
||||
<ul class="space-y-1">
|
||||
<ul class="space-y-0.5">
|
||||
<li v-for="item in group.items" :key="item.key">
|
||||
<Link
|
||||
:href="route(item.routeName)"
|
||||
:class="[
|
||||
'flex items-center gap-3 px-4 py-2 text-sm hover:bg-gray-100',
|
||||
'flex items-center gap-3 px-3 py-2.5 text-sm rounded-lg transition-all duration-150',
|
||||
isActive(item.active)
|
||||
? 'bg-gray-100 text-gray-900'
|
||||
: 'text-gray-600',
|
||||
? 'bg-primary-50 text-primary-700 font-medium shadow-sm'
|
||||
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900',
|
||||
]"
|
||||
:title="item.title"
|
||||
>
|
||||
@@ -336,10 +336,19 @@ function isActive(patterns) {
|
||||
<FontAwesomeIcon
|
||||
v-if="menuIconMap[item.key]"
|
||||
:icon="menuIconMap[item.key]"
|
||||
class="w-5 h-5 text-gray-600"
|
||||
:class="[
|
||||
'w-5 h-5 flex-shrink-0 transition-colors',
|
||||
isActive(item.active) ? 'text-primary-600' : 'text-gray-500',
|
||||
]"
|
||||
/>
|
||||
<!-- Title -->
|
||||
<span v-if="!sidebarCollapsed">{{ item.title }}</span>
|
||||
<span
|
||||
v-if="!sidebarCollapsed"
|
||||
class="truncate transition-opacity"
|
||||
:class="{ 'font-medium': isActive(item.active) }"
|
||||
>
|
||||
{{ item.title }}
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -352,13 +361,14 @@ function isActive(patterns) {
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<!-- Top bar -->
|
||||
<div
|
||||
class="h-16 bg-white border-b border-gray-100 px-4 flex items-center justify-between sticky top-0 z-30"
|
||||
class="h-16 bg-white border-b border-gray-200 px-4 flex items-center justify-between sticky top-0 z-30 backdrop-blur-sm bg-white/95 shadow-sm"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- Sidebar toggle -->
|
||||
<button
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@click="handleSidebarToggleClick()"
|
||||
class="inline-flex items-center justify-center w-9 h-9 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100"
|
||||
:title="sidebarCollapsed ? 'Razširi meni' : 'Skrči meni'"
|
||||
aria-label="Toggle sidebar"
|
||||
>
|
||||
@@ -377,11 +387,13 @@ function isActive(patterns) {
|
||||
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Button>
|
||||
<!-- Search trigger -->
|
||||
<button
|
||||
<Button
|
||||
variant="outline"
|
||||
size="default"
|
||||
@click="openSearch"
|
||||
class="inline-flex items-center gap-2 px-3 py-2 text-sm rounded-md border border-gray-200 text-gray-500 hover:text-gray-700 hover:border-gray-300"
|
||||
class="gap-2"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -389,7 +401,7 @@ function isActive(patterns) {
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-5 h-5"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
@@ -397,46 +409,52 @@ function isActive(patterns) {
|
||||
d="M21 21l-4.35-4.35m0 0A7.5 7.5 0 1010.5 18.5a7.5 7.5 0 006.15-1.85z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="hidden sm:inline">Globalni iskalnik</span>
|
||||
<span class="hidden sm:inline text-sm font-medium">Globalni iskalnik</span>
|
||||
<kbd
|
||||
class="hidden sm:inline ml-2 text-[10px] px-1.5 py-0.5 rounded border bg-gray-50"
|
||||
class="hidden sm:inline ml-2 text-[10px] px-1.5 py-0.5 rounded border border-gray-300 bg-gray-100 text-gray-600 font-medium"
|
||||
>Ctrl K</kbd
|
||||
>
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
<!-- Notifications + User drop menu --->
|
||||
<div class="flex items-center">
|
||||
<NotificationsBell class="mr-2" />
|
||||
<!-- Phone page quick access button -->
|
||||
<Link
|
||||
:href="route('phone.index')"
|
||||
class="inline-flex items-center justify-center w-9 h-9 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100 mr-2"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
:as-child="true"
|
||||
class="mr-2"
|
||||
title="Phone"
|
||||
>
|
||||
<FontAwesomeIcon :icon="faMobileScreenButton" class="h-5 w-5" />
|
||||
</Link>
|
||||
<Link :href="route('phone.index')">
|
||||
<FontAwesomeIcon :icon="faMobileScreenButton" class="h-5 w-5" />
|
||||
</Link>
|
||||
</Button>
|
||||
<div class="ms-3 relative">
|
||||
<Dropdown align="right" width="48">
|
||||
<template #trigger>
|
||||
<button
|
||||
v-if="$page.props.jetstream.managesProfilePhotos"
|
||||
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-gray-300 transition"
|
||||
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-primary-500 focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 transition-all hover:ring-2 hover:ring-gray-200"
|
||||
>
|
||||
<img
|
||||
class="h-8 w-8 rounded-full object-cover"
|
||||
class="h-8 w-8 rounded-full object-cover ring-2 ring-gray-100"
|
||||
:src="$page.props.auth.user.profile_photo_url"
|
||||
:alt="$page.props.auth.user.name"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<span v-else class="inline-flex rounded-md">
|
||||
<button
|
||||
<span v-else class="inline-flex">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="default"
|
||||
type="button"
|
||||
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none focus:bg-gray-50 active:bg-gray-50 transition ease-in-out duration-150"
|
||||
class="gap-2"
|
||||
>
|
||||
{{ $page.props.auth.user.name }}
|
||||
<svg
|
||||
class="ms-2 -me-0.5 h-4 w-4"
|
||||
class="h-4 w-4"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -449,7 +467,7 @@ function isActive(patterns) {
|
||||
d="M19.5 8.25l-7.5 7.5-7.5-7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@@ -477,7 +495,10 @@ function isActive(patterns) {
|
||||
</div>
|
||||
|
||||
<!-- Page Heading -->
|
||||
<header v-if="$slots.header" class="bg-white border-b shadow-sm">
|
||||
<header
|
||||
v-if="$slots.header"
|
||||
class="bg-white border-b border-gray-200 shadow-sm"
|
||||
>
|
||||
<div class="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8 space-y-2">
|
||||
<Breadcrumbs
|
||||
v-if="$page.props.breadcrumbs && $page.props.breadcrumbs.length"
|
||||
@@ -488,7 +509,7 @@ function isActive(patterns) {
|
||||
</header>
|
||||
|
||||
<!-- Page Content -->
|
||||
<main class="p-4">
|
||||
<main class="flex-1 p-4 sm:p-6">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
@@ -497,20 +518,7 @@ function isActive(patterns) {
|
||||
<!-- Global Search Modal -->
|
||||
<GlobalSearch :open="searchOpen" @update:open="(v) => (searchOpen = v)" />
|
||||
|
||||
<!-- Simple Toast -->
|
||||
<transition name="fade">
|
||||
<div
|
||||
v-if="showToast"
|
||||
class="fixed bottom-4 right-4 z-[100] px-4 py-3 rounded shadow-lg text-white"
|
||||
:class="{
|
||||
'bg-emerald-600': toastType === 'success',
|
||||
'bg-red-600': toastType === 'error',
|
||||
'bg-amber-500': toastType === 'warning',
|
||||
'bg-blue-600': toastType === 'info',
|
||||
}"
|
||||
>
|
||||
{{ toastMessage }}
|
||||
</div>
|
||||
</transition>
|
||||
<!-- Toast Notification Container -->
|
||||
<ToastContainer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -7,8 +7,15 @@ import Dropdown from "@/Components/Dropdown.vue";
|
||||
import DropdownLink from "@/Components/DropdownLink.vue";
|
||||
import GlobalSearch from "./Partials/GlobalSearch.vue";
|
||||
import NotificationsBell from "./Partials/NotificationsBell.vue";
|
||||
import Breadcrumbs from "@/Components/Breadcrumbs.vue";
|
||||
import ToastContainer from "@/Components/Toast/ToastContainer.vue";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { faDesktop } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faDesktop,
|
||||
faClipboardList,
|
||||
faCircleCheck,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
@@ -122,50 +129,63 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
<aside
|
||||
:class="[
|
||||
widthClass,
|
||||
'bg-white border-r border-gray-200 transition-all duration-200 z-50',
|
||||
'bg-white border-r border-gray-200 transition-all duration-300 ease-in-out z-50',
|
||||
isMobile
|
||||
? 'fixed inset-y-0 left-0 transform ' +
|
||||
? 'fixed inset-y-0 left-0 transform shadow-strong ' +
|
||||
(mobileSidebarOpen ? 'translate-x-0' : '-translate-x-full')
|
||||
: 'sticky top-0 h-screen overflow-y-auto',
|
||||
]"
|
||||
>
|
||||
<div class="h-16 px-4 flex items-center justify-between border-b">
|
||||
<Link :href="route('phone.index')" class="flex items-center gap-2">
|
||||
<ApplicationMark class="h-8 w-auto" />
|
||||
<span v-if="showLabels" class="text-sm font-semibold">Teren</span>
|
||||
<div class="h-16 px-4 flex items-center justify-between border-b border-gray-200 bg-white">
|
||||
<Link
|
||||
:href="route('phone.index')"
|
||||
class="flex items-center gap-2 hover:opacity-80 transition-opacity"
|
||||
>
|
||||
<ApplicationMark />
|
||||
<span
|
||||
v-if="showLabels"
|
||||
class="text-sm font-semibold text-gray-900 transition-opacity"
|
||||
>
|
||||
Teren
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
<nav class="py-4">
|
||||
<ul class="space-y-1">
|
||||
<nav class="py-4 overflow-y-auto">
|
||||
<ul class="space-y-0.5 px-2">
|
||||
<!-- Assigned jobs link -->
|
||||
<li>
|
||||
<Link
|
||||
:href="route('phone.index')"
|
||||
:class="[
|
||||
'flex items-center gap-3 px-4 py-2 text-sm hover:bg-gray-100',
|
||||
'flex items-center gap-3 px-3 py-2.5 text-sm rounded-lg transition-all duration-150',
|
||||
route().current('phone.index') ||
|
||||
(route().current('phone.case') && !isCompletedMode)
|
||||
? 'bg-gray-100 text-gray-900'
|
||||
: 'text-gray-600',
|
||||
? 'bg-primary-50 text-primary-700 font-medium shadow-sm'
|
||||
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900',
|
||||
]"
|
||||
title="Opravila"
|
||||
>
|
||||
<!-- clipboard-list icon -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
class="w-5 h-5"
|
||||
<FontAwesomeIcon
|
||||
:icon="faClipboardList"
|
||||
:class="[
|
||||
'w-5 h-5 flex-shrink-0 transition-colors',
|
||||
route().current('phone.index') ||
|
||||
(route().current('phone.case') && !isCompletedMode)
|
||||
? 'text-primary-600'
|
||||
: 'text-gray-500',
|
||||
]"
|
||||
/>
|
||||
<span
|
||||
v-if="showLabels"
|
||||
class="truncate transition-opacity"
|
||||
:class="{
|
||||
'font-medium':
|
||||
route().current('phone.index') ||
|
||||
(route().current('phone.case') && !isCompletedMode),
|
||||
}"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M9 6.75H7.5A2.25 2.25 0 005.25 9v9A2.25 2.25 0 007.5 20.25h9A2.25 2.25 0 0018.75 18v-9A2.25 2.25 0 0016.5 6.75H15M9 6.75A1.5 1.5 0 0010.5 5.25h3A1.5 1.5 0 0015 6.75M9 6.75A1.5 1.5 0 0110.5 8.25h3A1.5 1.5 0 0015 6.75M9 12h.008v.008H9V12zm0 3h.008v.008H9V15zm3-3h3m-3 3h3"
|
||||
/>
|
||||
</svg>
|
||||
<span v-if="showLabels">Opravila</span>
|
||||
Opravila
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
<!-- Completed today link -->
|
||||
@@ -173,30 +193,35 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
<Link
|
||||
:href="route('phone.completed')"
|
||||
:class="[
|
||||
'flex items-center gap-3 px-4 py-2 text-sm hover:bg-gray-100',
|
||||
'flex items-center gap-3 px-3 py-2.5 text-sm rounded-lg transition-all duration-150',
|
||||
route().current('phone.completed') ||
|
||||
(route().current('phone.case') && isCompletedMode)
|
||||
? 'bg-gray-100 text-gray-900'
|
||||
: 'text-gray-600',
|
||||
? 'bg-primary-50 text-primary-700 font-medium shadow-sm'
|
||||
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900',
|
||||
]"
|
||||
title="Zaključeno danes"
|
||||
>
|
||||
<!-- check-circle icon -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
class="w-5 h-5"
|
||||
<FontAwesomeIcon
|
||||
:icon="faCircleCheck"
|
||||
:class="[
|
||||
'w-5 h-5 flex-shrink-0 transition-colors',
|
||||
route().current('phone.completed') ||
|
||||
(route().current('phone.case') && isCompletedMode)
|
||||
? 'text-primary-600'
|
||||
: 'text-gray-500',
|
||||
]"
|
||||
/>
|
||||
<span
|
||||
v-if="showLabels"
|
||||
class="truncate transition-opacity"
|
||||
:class="{
|
||||
'font-medium':
|
||||
route().current('phone.completed') ||
|
||||
(route().current('phone.case') && isCompletedMode),
|
||||
}"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span v-if="showLabels">Zaključeno danes</span>
|
||||
Zaključeno danes
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -207,13 +232,14 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<!-- Top bar -->
|
||||
<div
|
||||
class="h-16 bg-white border-b border-gray-100 px-4 flex items-center justify-between sticky top-0 z-30"
|
||||
class="h-16 bg-white border-b border-gray-200 px-4 flex items-center justify-between sticky top-0 z-30 backdrop-blur-sm bg-white/95 shadow-sm"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- Sidebar toggle -->
|
||||
<button
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@click="handleSidebarToggleClick()"
|
||||
class="inline-flex items-center justify-center w-9 h-9 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100"
|
||||
:title="sidebarCollapsed ? 'Razširi meni' : 'Skrči meni'"
|
||||
aria-label="Toggle sidebar"
|
||||
>
|
||||
@@ -231,11 +257,13 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Button>
|
||||
<!-- Search trigger -->
|
||||
<button
|
||||
<Button
|
||||
variant="outline"
|
||||
size="default"
|
||||
@click="openSearch"
|
||||
class="inline-flex items-center gap-2 px-3 py-2 text-sm rounded-md border border-gray-200 text-gray-500 hover:text-gray-700 hover:border-gray-300"
|
||||
class="gap-2"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -243,7 +271,7 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-5 h-5"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
@@ -251,46 +279,52 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
d="M21 21l-4.35-4.35m0 0A7.5 7.5 0 1010.5 18.5a7.5 7.5 0 006.15-1.85z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="hidden sm:inline">Globalni iskalnik</span>
|
||||
<span class="hidden sm:inline text-sm font-medium">Globalni iskalnik</span>
|
||||
<kbd
|
||||
class="hidden sm:inline ml-2 text-[10px] px-1.5 py-0.5 rounded border bg-gray-50"
|
||||
class="hidden sm:inline ml-2 text-[10px] px-1.5 py-0.5 rounded border border-gray-300 bg-gray-100 text-gray-600 font-medium"
|
||||
>Ctrl K</kbd
|
||||
>
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
<!-- Notifications + User drop menu + Desktop switch button -->
|
||||
<div class="flex items-center">
|
||||
<NotificationsBell class="mr-2" />
|
||||
<!-- Desktop page quick access button -->
|
||||
<Link
|
||||
:href="route('clientCase')"
|
||||
class="inline-flex items-center justify-center w-9 h-9 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100 mr-2"
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
:as-child="true"
|
||||
class="mr-2"
|
||||
title="Desktop"
|
||||
>
|
||||
<FontAwesomeIcon :icon="faDesktop" class="h-5 w-5" />
|
||||
</Link>
|
||||
<Link :href="route('clientCase')">
|
||||
<FontAwesomeIcon :icon="faDesktop" class="h-5 w-5" />
|
||||
</Link>
|
||||
</Button>
|
||||
<div class="ms-3 relative">
|
||||
<Dropdown align="right" width="48">
|
||||
<template #trigger>
|
||||
<button
|
||||
v-if="$page.props.jetstream.managesProfilePhotos"
|
||||
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-gray-300 transition"
|
||||
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-primary-500 focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 transition-all hover:ring-2 hover:ring-gray-200"
|
||||
>
|
||||
<img
|
||||
class="h-8 w-8 rounded-full object-cover"
|
||||
class="h-8 w-8 rounded-full object-cover ring-2 ring-gray-100"
|
||||
:src="$page.props.auth.user.profile_photo_url"
|
||||
:alt="$page.props.auth.user.name"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<span v-else class="inline-flex rounded-md">
|
||||
<button
|
||||
<span v-else class="inline-flex">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="default"
|
||||
type="button"
|
||||
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none focus:bg-gray-50 active:bg-gray-50 transition ease-in-out duration-150"
|
||||
class="gap-2"
|
||||
>
|
||||
{{ $page.props.auth.user.name }}
|
||||
<svg
|
||||
class="ms-2 -me-0.5 h-4 w-4"
|
||||
class="h-4 w-4"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -303,7 +337,7 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
d="M19.5 8.25l-7.5 7.5-7.5-7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@@ -331,14 +365,21 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
</div>
|
||||
|
||||
<!-- Page Heading -->
|
||||
<header v-if="$slots.header" class="bg-white border-b shadow-sm">
|
||||
<header
|
||||
v-if="$slots.header"
|
||||
class="bg-white border-b border-gray-200 shadow-sm"
|
||||
>
|
||||
<div class="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8 space-y-2">
|
||||
<Breadcrumbs
|
||||
v-if="$page.props.breadcrumbs && $page.props.breadcrumbs.length"
|
||||
:breadcrumbs="$page.props.breadcrumbs"
|
||||
/>
|
||||
<slot name="header" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Page Content -->
|
||||
<main class="p-4">
|
||||
<main class="flex-1 p-4 sm:p-6">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
@@ -347,20 +388,7 @@ const closeSearch = () => (searchOpen.value = false);
|
||||
<!-- Global Search Modal -->
|
||||
<GlobalSearch :open="searchOpen" @update:open="(v) => (searchOpen = v)" />
|
||||
|
||||
<!-- Simple Toast -->
|
||||
<transition name="fade">
|
||||
<div
|
||||
v-if="showToast"
|
||||
class="fixed bottom-4 right-4 z-[100] px-4 py-3 rounded shadow-lg text-white"
|
||||
:class="{
|
||||
'bg-emerald-600': toastType === 'success',
|
||||
'bg-red-600': toastType === 'error',
|
||||
'bg-amber-500': toastType === 'warning',
|
||||
'bg-blue-600': toastType === 'info',
|
||||
}"
|
||||
>
|
||||
{{ toastMessage }}
|
||||
</div>
|
||||
</transition>
|
||||
<!-- Toast Notification Container -->
|
||||
<ToastContainer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { FwbInput } from "flowbite-vue";
|
||||
import { Input } from "@/Components/ui/input";
|
||||
import axios from "axios";
|
||||
import { debounce } from "lodash";
|
||||
import { SearchIcon } from "@/Utilities/Icons";
|
||||
@@ -67,63 +67,63 @@ onUnmounted(() => window.removeEventListener("keydown", onKeydown));
|
||||
@click.self="isOpen = false"
|
||||
>
|
||||
<div
|
||||
class="w-full max-w-3xl rounded-2xl border border-white/10 bg-white/80 dark:bg-slate-900/85 backdrop-blur-xl shadow-2xl ring-1 ring-black/5 overflow-hidden"
|
||||
class="w-full max-w-3xl rounded-2xl border border-white/10 bg-white/80 backdrop-blur-xl shadow-2xl ring-1 ring-black/5 overflow-hidden"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<div
|
||||
class="p-4 border-b border-slate-200/60 dark:border-slate-700/60"
|
||||
class="p-4 border-b border-slate-200/60"
|
||||
ref="inputWrap"
|
||||
>
|
||||
<div class="relative">
|
||||
<FwbInput
|
||||
v-model="query"
|
||||
placeholder="Išči po naročnikih ali primerih (Ctrl+K za zapiranje)"
|
||||
size="md"
|
||||
class="w-full [&>div]:rounded-xl"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="relative">
|
||||
<div class="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500">
|
||||
<SearchIcon />
|
||||
</template>
|
||||
</FwbInput>
|
||||
<button
|
||||
v-if="query"
|
||||
@click="query = ''"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 text-xs text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
|
||||
>
|
||||
ESC
|
||||
</button>
|
||||
</div>
|
||||
<Input
|
||||
v-model="query"
|
||||
placeholder="Išči po naročnikih ali primerih (Ctrl+K za zapiranje)"
|
||||
class="w-full pl-10 pr-16 rounded-xl"
|
||||
/>
|
||||
<button
|
||||
v-if="query"
|
||||
@click="query = ''"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 text-xs text-slate-500 hover:text-slate-700"
|
||||
>
|
||||
ESC
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="max-h-[65vh] overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-slate-300 dark:scrollbar-thumb-slate-600"
|
||||
class="max-h-[65vh] overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-slate-300"
|
||||
>
|
||||
<div
|
||||
v-if="!query"
|
||||
class="p-8 text-sm text-slate-500 dark:text-slate-400 text-center space-y-2"
|
||||
class="p-8 text-sm text-slate-500 text-center space-y-2"
|
||||
>
|
||||
<p>Začni tipkati za iskanje.</p>
|
||||
<p class="text-xs">
|
||||
Namig: uporabi
|
||||
<kbd
|
||||
class="px-1.5 py-0.5 bg-slate-100 dark:bg-slate-700 rounded font-mono text-[10px]"
|
||||
class="px-1.5 py-0.5 bg-slate-100 rounded font-mono text-[10px]"
|
||||
>Ctrl</kbd
|
||||
>
|
||||
+
|
||||
<kbd
|
||||
class="px-1.5 py-0.5 bg-slate-100 dark:bg-slate-700 rounded font-mono text-[10px]"
|
||||
class="px-1.5 py-0.5 bg-slate-100 rounded font-mono text-[10px]"
|
||||
>K</kbd
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<div v-else class="divide-y divide-slate-200/70 dark:divide-slate-700/50">
|
||||
<div v-else class="divide-y divide-slate-200/70">
|
||||
<div v-if="result.clients.length" class="py-3">
|
||||
<div
|
||||
class="flex items-center justify-between px-5 pb-1 text-[11px] font-semibold tracking-wide uppercase text-slate-500 dark:text-slate-400"
|
||||
class="flex items-center justify-between px-5 pb-1 text-[11px] font-semibold tracking-wide uppercase text-slate-500"
|
||||
>
|
||||
<span>Naročniki</span>
|
||||
<span
|
||||
class="rounded bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300 px-2 py-0.5 text-[10px]"
|
||||
class="rounded bg-slate-100 text-slate-600 px-2 py-0.5 text-[10px]"
|
||||
>{{ result.clients.length }}</span
|
||||
>
|
||||
</div>
|
||||
@@ -131,7 +131,7 @@ onUnmounted(() => window.removeEventListener("keydown", onKeydown));
|
||||
<li v-for="client in result.clients" :key="client.client_uuid">
|
||||
<Link
|
||||
:href="route('client.show', { uuid: client.client_uuid })"
|
||||
class="group flex items-center gap-3 w-full rounded-lg px-3 py-2 text-sm hover:bg-indigo-50/70 dark:hover:bg-slate-700/60 transition"
|
||||
class="group flex items-center gap-3 w-full rounded-lg px-3 py-2 text-sm hover:bg-indigo-50/70 transition"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
<span
|
||||
@@ -139,7 +139,7 @@ onUnmounted(() => window.removeEventListener("keydown", onKeydown));
|
||||
>C</span
|
||||
>
|
||||
<span
|
||||
class="text-slate-700 dark:text-slate-200 group-hover:text-slate-900 dark:group-hover:text-white"
|
||||
class="text-slate-700 group-hover:text-slate-900"
|
||||
>{{ client.full_name }}</span
|
||||
>
|
||||
</Link>
|
||||
@@ -148,11 +148,11 @@ onUnmounted(() => window.removeEventListener("keydown", onKeydown));
|
||||
</div>
|
||||
<div v-if="result.client_cases.length" class="py-3">
|
||||
<div
|
||||
class="flex items-center justify-between px-5 pb-1 text-[11px] font-semibold tracking-wide uppercase text-slate-500 dark:text-slate-400"
|
||||
class="flex items-center justify-between px-5 pb-1 text-[11px] font-semibold tracking-wide uppercase text-slate-500"
|
||||
>
|
||||
<span>Primeri</span>
|
||||
<span
|
||||
class="rounded bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300 px-2 py-0.5 text-[10px]"
|
||||
class="rounded bg-slate-100 text-slate-600 px-2 py-0.5 text-[10px]"
|
||||
>{{ result.client_cases.length }}</span
|
||||
>
|
||||
</div>
|
||||
@@ -160,7 +160,7 @@ onUnmounted(() => window.removeEventListener("keydown", onKeydown));
|
||||
<li
|
||||
v-for="clientcase in result.client_cases"
|
||||
:key="clientcase.case_uuid"
|
||||
class="rounded-xl border border-slate-200/70 dark:border-slate-700/50 bg-white/70 dark:bg-slate-800/70 px-4 py-3 shadow-sm hover:shadow-md transition flex flex-col gap-1"
|
||||
class="rounded-xl border border-slate-200/70 bg-white/70 px-4 py-3 shadow-sm hover:shadow-md transition flex flex-col gap-1"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Link
|
||||
@@ -169,7 +169,7 @@ onUnmounted(() => window.removeEventListener("keydown", onKeydown));
|
||||
client_case: clientcase.case_uuid,
|
||||
})
|
||||
"
|
||||
class="text-left font-medium hover:underline leading-tight text-slate-800 dark:text-slate-100"
|
||||
class="text-left font-medium hover:underline leading-tight text-slate-800"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
{{ clientcase.full_name }}
|
||||
@@ -232,7 +232,7 @@ onUnmounted(() => window.removeEventListener("keydown", onKeydown));
|
||||
</div>
|
||||
<div
|
||||
v-if="!result.clients.length && !result.client_cases.length"
|
||||
class="p-8 text-center text-sm text-slate-500 dark:text-slate-400"
|
||||
class="p-8 text-center text-sm text-slate-500"
|
||||
>
|
||||
Ni rezultatov.
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user