Changes
This commit is contained in:
@@ -1,8 +1,18 @@
|
||||
<script setup>
|
||||
import { Input } from "@/Components/ui/input";
|
||||
import { Badge } from "@/Components/ui/badge";
|
||||
import { Card, CardContent } from "@/Components/ui/card";
|
||||
import { Separator } from "@/Components/ui/separator";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/Components/ui/dialog";
|
||||
import axios from "axios";
|
||||
import { debounce } from "lodash";
|
||||
import { SearchIcon } from "@/Utilities/Icons";
|
||||
import { SearchIcon, XIcon } from "lucide-vue-next";
|
||||
import { onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { Link } from "@inertiajs/vue3";
|
||||
|
||||
@@ -55,203 +65,169 @@ onMounted(() => window.addEventListener("keydown", onKeydown));
|
||||
onUnmounted(() => window.removeEventListener("keydown", onKeydown));
|
||||
</script>
|
||||
<template>
|
||||
<teleport to="body">
|
||||
<transition name="fade">
|
||||
<div v-if="isOpen" class="fixed inset-0 z-50">
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-br from-slate-900/60 to-slate-800/60 backdrop-blur-sm"
|
||||
@click="isOpen = false"
|
||||
></div>
|
||||
<div
|
||||
class="absolute inset-0 flex items-start justify-center p-4 pt-20 sm:pt-28"
|
||||
@click.self="isOpen = false"
|
||||
>
|
||||
<div
|
||||
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"
|
||||
<Dialog :open="isOpen" @update:open="(v) => (isOpen = v)">
|
||||
<DialogContent class="max-w-3xl p-0 gap-0 [&>button]:hidden">
|
||||
<div class="p-4 border-b" ref="inputWrap">
|
||||
<div class="relative">
|
||||
<SearchIcon
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"
|
||||
/>
|
||||
<Input
|
||||
v-model="query"
|
||||
placeholder="Išči po naročnikih ali primerih (ESC za zapiranje)"
|
||||
class="w-full pl-10 pr-16"
|
||||
/>
|
||||
<button
|
||||
v-if="query"
|
||||
@click="query = ''"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 p-1 rounded hover:bg-accent"
|
||||
>
|
||||
<XIcon class="h-4 w-4 text-muted-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="max-h-[65vh] overflow-y-auto">
|
||||
<div
|
||||
v-if="!query"
|
||||
class="p-8 text-sm text-muted-foreground text-center space-y-2"
|
||||
>
|
||||
<p>Začni tipkati za iskanje.</p>
|
||||
<p class="text-xs">
|
||||
Namig: uporabi <Badge variant="secondary" class="font-mono">Ctrl</Badge> +
|
||||
<Badge variant="secondary" class="font-mono">K</Badge>
|
||||
</p>
|
||||
</div>
|
||||
<div v-else class="space-y-4 p-4">
|
||||
<!-- Clients Results -->
|
||||
<div v-if="result.clients.length">
|
||||
<div
|
||||
class="p-4 border-b border-slate-200/60"
|
||||
ref="inputWrap"
|
||||
class="flex items-center justify-between pb-2 text-xs font-semibold tracking-wide uppercase text-muted-foreground"
|
||||
>
|
||||
<div class="relative">
|
||||
<div class="relative">
|
||||
<div class="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500">
|
||||
<SearchIcon />
|
||||
</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>
|
||||
<span>Naročniki</span>
|
||||
<Badge variant="secondary">{{ result.clients.length }}</Badge>
|
||||
</div>
|
||||
<div
|
||||
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 text-center space-y-2"
|
||||
<div class="space-y-1">
|
||||
<Link
|
||||
v-for="client in result.clients"
|
||||
:key="client.client_uuid"
|
||||
: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-accent transition"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
<p>Začni tipkati za iskanje.</p>
|
||||
<p class="text-xs">
|
||||
Namig: uporabi
|
||||
<kbd
|
||||
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 rounded font-mono text-[10px]"
|
||||
>K</kbd
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<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"
|
||||
>
|
||||
<span>Naročniki</span>
|
||||
<span
|
||||
class="rounded bg-slate-100 text-slate-600 px-2 py-0.5 text-[10px]"
|
||||
>{{ result.clients.length }}</span
|
||||
>
|
||||
</div>
|
||||
<ul role="list" class="px-2 space-y-1">
|
||||
<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 transition"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
<span
|
||||
class="shrink-0 w-6 h-6 rounded bg-indigo-100 text-indigo-600 flex items-center justify-center text-[11px] font-semibold group-hover:bg-indigo-200"
|
||||
>C</span
|
||||
>
|
||||
<span
|
||||
class="text-slate-700 group-hover:text-slate-900"
|
||||
>{{ client.full_name }}</span
|
||||
>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</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"
|
||||
>
|
||||
<span>Primeri</span>
|
||||
<span
|
||||
class="rounded bg-slate-100 text-slate-600 px-2 py-0.5 text-[10px]"
|
||||
>{{ result.client_cases.length }}</span
|
||||
>
|
||||
</div>
|
||||
<ul role="list" class="px-2 space-y-1">
|
||||
<li
|
||||
v-for="clientcase in result.client_cases"
|
||||
:key="clientcase.case_uuid"
|
||||
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
|
||||
:href="
|
||||
route('clientCase.show', {
|
||||
client_case: clientcase.case_uuid,
|
||||
})
|
||||
"
|
||||
class="text-left font-medium hover:underline leading-tight text-slate-800"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
{{ clientcase.full_name }}
|
||||
</Link>
|
||||
<template v-if="clientcase.contract_reference">
|
||||
<span
|
||||
class="font-mono text-[11px] tracking-tight text-indigo-600 bg-indigo-50 border border-indigo-200 rounded px-1.5 py-0.5 whitespace-nowrap shadow-sm"
|
||||
>
|
||||
{{ clientcase.contract_reference }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
clientcase.contract_segments &&
|
||||
clientcase.contract_segments.length
|
||||
"
|
||||
class="flex flex-wrap gap-1 mt-1"
|
||||
>
|
||||
<Link
|
||||
v-for="seg in clientcase.contract_segments"
|
||||
:key="seg.id || seg.name || seg"
|
||||
:href="
|
||||
route('clientCase.show', {
|
||||
client_case: clientcase.case_uuid,
|
||||
}) +
|
||||
'?segment=' +
|
||||
(seg.id || seg)
|
||||
"
|
||||
class="group/seg text-[10px] uppercase tracking-wide bg-gradient-to-br from-purple-50 to-purple-100 text-purple-700 border border-purple-200 px-1.5 py-0.5 rounded hover:from-purple-100 hover:to-purple-200 hover:border-purple-300 transition"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
{{ seg.name || seg }}
|
||||
</Link>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="
|
||||
clientcase.case_segments && clientcase.case_segments.length
|
||||
"
|
||||
class="flex flex-wrap gap-1 mt-1"
|
||||
>
|
||||
<Link
|
||||
v-for="seg in clientcase.case_segments"
|
||||
:key="seg.id || seg.name"
|
||||
:href="
|
||||
route('clientCase.show', {
|
||||
client_case: clientcase.case_uuid,
|
||||
}) +
|
||||
'?segment=' +
|
||||
(seg.id || seg)
|
||||
"
|
||||
class="text-[10px] uppercase tracking-wide bg-slate-100 text-slate-600 border border-slate-200 px-1.5 py-0.5 rounded hover:bg-slate-200 hover:text-slate-700 transition"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
{{ seg.name }}
|
||||
</Link>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
v-if="!result.clients.length && !result.client_cases.length"
|
||||
class="p-8 text-center text-sm text-slate-500"
|
||||
<Badge
|
||||
variant="outline"
|
||||
class="shrink-0 w-6 h-6 flex items-center justify-center"
|
||||
>C</Badge
|
||||
>
|
||||
Ni rezultatov.
|
||||
</div>
|
||||
</div>
|
||||
<span class="font-medium">{{ client.full_name }}</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator v-if="result.clients.length && result.client_cases.length" />
|
||||
|
||||
<!-- Client Cases Results -->
|
||||
<div v-if="result.client_cases.length">
|
||||
<div
|
||||
class="flex items-center justify-between pb-2 text-xs font-semibold tracking-wide uppercase text-muted-foreground"
|
||||
>
|
||||
<span>Primeri</span>
|
||||
<Badge variant="secondary">{{ result.client_cases.length }}</Badge>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Card
|
||||
v-for="clientcase in result.client_cases"
|
||||
:key="clientcase.case_uuid"
|
||||
class="hover:shadow-md transition p-0"
|
||||
>
|
||||
<CardContent class="p-3 space-y-2">
|
||||
<div class="space-y-1">
|
||||
<Link
|
||||
:href="
|
||||
route('clientCase.show', {
|
||||
client_case: clientcase.case_uuid,
|
||||
})
|
||||
"
|
||||
class="text-sm font-medium hover:underline block"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
{{ clientcase.full_name }}
|
||||
</Link>
|
||||
<div
|
||||
v-if="clientcase.client_full_name"
|
||||
class="text-xs text-muted-foreground"
|
||||
>
|
||||
Naročnik: {{ clientcase.client_full_name }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="clientcase.contract_reference"
|
||||
class="flex items-center gap-1"
|
||||
>
|
||||
<Badge variant="outline" class="font-mono text-xs">
|
||||
{{ clientcase.contract_reference }}
|
||||
</Badge>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
clientcase.contract_segments && clientcase.contract_segments.length
|
||||
"
|
||||
class="flex flex-wrap gap-1"
|
||||
>
|
||||
<Link
|
||||
v-for="seg in clientcase.contract_segments"
|
||||
:key="seg.id || seg.name || seg"
|
||||
:href="
|
||||
route('clientCase.show', {
|
||||
client_case: clientcase.case_uuid,
|
||||
}) +
|
||||
'?segment=' +
|
||||
(seg.id || seg)
|
||||
"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
<Badge variant="secondary" class="text-xs uppercase">
|
||||
{{ seg.name || seg }}
|
||||
</Badge>
|
||||
</Link>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="
|
||||
clientcase.case_segments && clientcase.case_segments.length
|
||||
"
|
||||
class="flex flex-wrap gap-1"
|
||||
>
|
||||
<Link
|
||||
v-for="seg in clientcase.case_segments"
|
||||
:key="seg.id || seg.name"
|
||||
:href="
|
||||
route('clientCase.show', {
|
||||
client_case: clientcase.case_uuid,
|
||||
}) +
|
||||
'?segment=' +
|
||||
(seg.id || seg)
|
||||
"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
<Badge variant="outline" class="text-xs uppercase">
|
||||
{{ seg.name }}
|
||||
</Badge>
|
||||
</Link>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- No Results -->
|
||||
<div
|
||||
v-if="!result.clients.length && !result.client_cases.length"
|
||||
class="p-8 text-center text-sm text-muted-foreground"
|
||||
>
|
||||
Ni rezultatov.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</teleport>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user