Sync progress
This commit is contained in:
@@ -26,33 +26,84 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<main class="grid h-screen w-full grid-cols-5 overflow-hidden bg-zinc-200/50 tracking-tight">
|
||||
<aside class="col-span-1 flex flex-col border-r bg-zinc-100">
|
||||
<div class="border-b border-zinc-200 bg-white p-4">
|
||||
<p class="mt-2 mb-2 text-center text-xl font-bold tracking-widest text-zinc-800 uppercase">
|
||||
Rota
|
||||
</p>
|
||||
<main
|
||||
class="grid h-screen w-full grid-cols-5 overflow-hidden bg-zinc-200/50 font-sans tracking-tight antialiased"
|
||||
>
|
||||
<aside
|
||||
class="col-span-1 flex flex-col border-r border-zinc-200 bg-zinc-50/50 font-sans antialiased"
|
||||
>
|
||||
<div class="flex justify-center border p-3 font-sans">
|
||||
<h1 class="text-xl font-black tracking-tight uppercase">Rota Scheduler</h1>
|
||||
</div>
|
||||
|
||||
<nav class="flex flex-1 flex-col">
|
||||
{#each steps as step}
|
||||
<button
|
||||
onclick={() => (rota.currentStep = step.id)}
|
||||
class="flex flex-1 flex-col justify-center border-b border-zinc-800/20 px-8 transition-all last:border-b-0
|
||||
{rota.currentStep === step.id
|
||||
? 'bg-blue-900/50 text-white'
|
||||
: 'text-zinc-500 hover:bg-zinc-800/50'}"
|
||||
>
|
||||
<span class="text-xs font-bold uppercase">ΒΗΜΑ {step.id}</span>
|
||||
<span class="font-medium">{step.title}</span>
|
||||
</button>
|
||||
{/each}
|
||||
<div class="border-t border-zinc-200 bg-white p-4">
|
||||
<p class="text-center text-[10px] font-bold tracking-widest text-zinc-500 uppercase">
|
||||
v1.0.0-Beta
|
||||
</p>
|
||||
<nav class="relative flex-1 p-6">
|
||||
<div class="absolute top-10 bottom-10 left-9.75 w-0.5 bg-zinc-200"></div>
|
||||
|
||||
<div class="relative flex h-full flex-col justify-between">
|
||||
{#each steps as step}
|
||||
<button
|
||||
onclick={() => (rota.currentStep = step.id)}
|
||||
class="group relative z-10 flex items-center gap-4 py-4 transition-all"
|
||||
>
|
||||
<div
|
||||
class="flex size-8 items-center justify-center rounded-full border-2 transition-all duration-300
|
||||
{rota.currentStep === step.id
|
||||
? 'bg-slate-800 text-white'
|
||||
: rota.currentStep > step.id
|
||||
? 'bg-emerald-600 text-white'
|
||||
: 'bg-white text-zinc-400'}"
|
||||
>
|
||||
{#if rota.currentStep > step.id}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="size-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
{:else}
|
||||
<span class="text-xs font-bold">{step.id}</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-start">
|
||||
<span
|
||||
class="text-[10px] font-bold tracking-widest uppercase
|
||||
{rota.currentStep === step.id ? 'text-black-800' : 'text-zinc-400'}"
|
||||
>
|
||||
ΒΗΜΑ {step.id}
|
||||
</span>
|
||||
<span
|
||||
class="text-sm font-bold tracking-tight
|
||||
{rota.currentStep === step.id ? 'text-zinc-900' : 'text-zinc-500'}"
|
||||
>
|
||||
{step.title}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="border-t border-zinc-200 bg-white p-6">
|
||||
<div class="rounded-xl border border-zinc-100 bg-zinc-50 p-4">
|
||||
<div class="mb-2 flex items-center justify-between">
|
||||
<span class="text-[10px] font-bold text-zinc-500 uppercase">ΟΛΟΚΛΗΡΩΣΗ</span>
|
||||
<span class="text-[10px] font-bold text-zinc-500"
|
||||
>{(((rota.currentStep - 1) / (steps.length - 1)) * 100).toFixed(0)}%</span
|
||||
>
|
||||
</div>
|
||||
<div class="h-1.5 w-full overflow-hidden rounded-full bg-zinc-200">
|
||||
<div
|
||||
class="h-full bg-emerald-600 transition-all duration-500"
|
||||
style="width: {(rota.currentStep / steps.length) * 100}%"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<section class="col-span-4 flex flex-col overflow-y-auto p-12">
|
||||
|
||||
@@ -29,28 +29,7 @@
|
||||
<p class="text-sm text-zinc-500">{steps[rota.currentStep - 1].description}</p>
|
||||
</header>
|
||||
|
||||
{#if rota.forbiddenPairs.length === 0}
|
||||
<div class="rounded-3xl border-2 border-dashed border-zinc-200 bg-white/50 py-16 text-center">
|
||||
<div class="mx-auto mb-3 flex size-12 items-center justify-center rounded-full bg-zinc-100">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="text-zinc-500"
|
||||
><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /><circle cx="9" cy="7" r="4" /><path
|
||||
d="M22 21v-2a4 4 0 0 0-3-3.87"
|
||||
/><path d="M16 3.13a4 4 0 0 1 0 7.75" /></svg
|
||||
>
|
||||
</div>
|
||||
<p class="text-sm font-medium text-zinc-500">Δεν έχουν οριστεί περιορισμοί.</p>
|
||||
</div>
|
||||
{:else}
|
||||
{#if rota.forbiddenPairs.length > 0}
|
||||
<div class="space-y-3">
|
||||
{#each rota.forbiddenPairs as pair, i (pair)}
|
||||
<div
|
||||
|
||||
@@ -36,37 +36,68 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header class="mb-2">
|
||||
<header class="mb-6">
|
||||
<p class="text-sm text-zinc-500">{steps[rota.currentStep - 1].description}</p>
|
||||
</header>
|
||||
<div class="grid grid-cols-2 gap-4 rounded-2xl border border-zinc-200 bg-white p-6">
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<p class="ml-1 text-[10px] font-black tracking-widest text-zinc-500 uppercase">Month</p>
|
||||
<select
|
||||
bind:value={rota.selectedMonth}
|
||||
class="w-full rounded-xl border border-zinc-200 bg-zinc-50 px-2 py-2 font-semibold text-zinc-600 outline-none focus:border-blue-600 focus:ring-2 focus:ring-blue-600/10"
|
||||
>
|
||||
{#each monthOptions as month}
|
||||
<option value={month.value}>{month.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<p class="ml-1 text-[10px] font-black tracking-widest text-zinc-500 uppercase">MONTH</p>
|
||||
<div class="relative">
|
||||
<select
|
||||
bind:value={rota.selectedMonth}
|
||||
class="w-full appearance-none rounded-xl border border-zinc-200 bg-white px-4 py-3 font-semibold text-zinc-700 transition-all outline-none focus:border-zinc-400 focus:ring-4 focus:ring-zinc-100"
|
||||
>
|
||||
{#each monthOptions as month}
|
||||
<option value={month.value}>{month.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<div class="pointer-events-none absolute top-1/2 right-4 -translate-y-1/2 text-zinc-400">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"><path d="m6 9 6 6 6-6" /></svg
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<p class="ml-1 text-[10px] font-black tracking-widest text-zinc-500 uppercase">Year</p>
|
||||
<select
|
||||
bind:value={rota.selectedYear}
|
||||
class="w-full rounded-xl border border-zinc-200 bg-zinc-50 px-2 py-2 font-semibold text-zinc-600 outline-none focus:border-blue-600 focus:ring-2 focus:ring-blue-600/10"
|
||||
>
|
||||
{#each yearOptions as year}
|
||||
<option value={year}>{year}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<p class="ml-1 text-[10px] font-black tracking-widest text-zinc-500 uppercase">YEAR</p>
|
||||
<div class="relative">
|
||||
<select
|
||||
bind:value={rota.selectedYear}
|
||||
class="w-full appearance-none rounded-xl border border-zinc-200 bg-white px-4 py-3 font-semibold text-zinc-700 transition-all outline-none focus:border-zinc-400 focus:ring-4 focus:ring-zinc-100"
|
||||
>
|
||||
{#each yearOptions as year}
|
||||
<option value={year}>{year}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<div class="pointer-events-none absolute top-1/2 right-4 -translate-y-1/2 text-zinc-400">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"><path d="m6 9 6 6 6-6" /></svg
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-4 mt-8 space-y-2">
|
||||
<p class="ml-1 text-[10px] font-black tracking-widest text-zinc-500 uppercase">Holidays</p>
|
||||
<div class="mt-8 space-y-2">
|
||||
<p class="ml-1 text-[10px] font-black tracking-widest text-zinc-500 uppercase">HOLIDAYS</p>
|
||||
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
@@ -74,45 +105,47 @@
|
||||
<Button
|
||||
{...props}
|
||||
variant="outline"
|
||||
class="w-full justify-start rounded-xl border-zinc-200 bg-white px-4 py-5 font-normal hover:bg-zinc-50"
|
||||
class="flex h-12 w-full items-center justify-between rounded-xl border-zinc-200 bg-white px-5 font-normal transition-all hover:bg-zinc-50"
|
||||
>
|
||||
<span class="mr-2 text-zinc-500"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mr-3 text-teal-800"
|
||||
>
|
||||
<path d="M8 2v4" /><path d="M16 2v4" /><rect
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-zinc-500">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
x="3"
|
||||
y="4"
|
||||
rx="2"
|
||||
/><path d="m3 10 18 18" /><path d="m21 10-18 18" />
|
||||
</svg></span
|
||||
>
|
||||
{#if rota.holidays.length > 0}
|
||||
<span class="font-bold text-teal-800">
|
||||
Επιλέχθηκαν {rota.holidays.length}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="text-teal-800"
|
||||
>
|
||||
<path d="M8 2v4" /><path d="M16 2v4" /><rect
|
||||
width="18"
|
||||
height="18"
|
||||
x="3"
|
||||
y="4"
|
||||
rx="2"
|
||||
/><path d="m3 10 18 18" /><path d="m21 10-18 18" />
|
||||
</svg>
|
||||
</span>
|
||||
{:else}
|
||||
<span class="text-zinc-500">Αργίες</span>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-col items-start leading-tight">
|
||||
{#if rota.holidays.length > 0}
|
||||
<span class="text-sm font-bold text-teal-800"
|
||||
>Επιλέχθηκαν {rota.holidays.length}</span
|
||||
>
|
||||
{:else}
|
||||
<span class="text-sm font-medium text-zinc-500">Αργίες</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
{/snippet}
|
||||
</Popover.Trigger>
|
||||
|
||||
<Popover.Content
|
||||
class="z-50 rounded-2xl border border-zinc-200 bg-white p-4"
|
||||
sideOffset={8}
|
||||
>
|
||||
<Popover.Content class="z-50 rounded-2xl border border-zinc-200 bg-white p-4" sideOffset={8}>
|
||||
<Calendar.Root
|
||||
type="multiple"
|
||||
placeholder={rota.projectMonth}
|
||||
@@ -124,7 +157,6 @@
|
||||
<Calendar.Heading
|
||||
class="items-center justify-between pb-4 text-center text-sm font-bold text-zinc-800"
|
||||
/>
|
||||
|
||||
<div class="flex flex-col gap-4 sm:flex-row">
|
||||
{#each months as month}
|
||||
<Calendar.Grid>
|
||||
@@ -147,15 +179,8 @@
|
||||
<div
|
||||
{...props}
|
||||
class="flex size-8 items-center justify-center rounded-lg text-sm transition-all
|
||||
hover:bg-teal-100 hover:text-teal-800
|
||||
data-outside-month:opacity-20 data-selected:bg-teal-800 data-selected:font-bold
|
||||
data-selected:text-white
|
||||
data-unavailable:pointer-events-none
|
||||
data-unavailable:cursor-not-allowed
|
||||
data-unavailable:bg-zinc-200
|
||||
data-unavailable:text-zinc-500
|
||||
data-unavailable:line-through
|
||||
data-unavailable:opacity-50"
|
||||
hover:bg-teal-100 hover:text-teal-800
|
||||
data-outside-month:opacity-20 data-selected:bg-teal-800 data-selected:font-bold data-selected:text-white"
|
||||
>
|
||||
{date.day}
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ export class RotaState {
|
||||
selectedYear = $state(2026);
|
||||
holidays = $state<CalendarDate[]>([]);
|
||||
forbiddenPairs = $state<ForbiddenPair[]>([]);
|
||||
|
||||
|
||||
projectMonth = $derived(new CalendarDate(this.selectedYear, this.selectedMonth, 1));
|
||||
projectMonthDays = $derived(this.projectMonth.calendar.getDaysInMonth(this.projectMonth));
|
||||
daysArray = $derived(Array.from({ length: this.projectMonthDays }, (_, i) => i + 1));
|
||||
@@ -38,7 +38,7 @@ export class RotaState {
|
||||
manualShifts: [],
|
||||
maxShifts: undefined,
|
||||
allowedTypes: ["OpenAsFirst", "OpenAsSecond", "Closed"],
|
||||
hasReducedLoad: false,
|
||||
hasReducedLoad: false
|
||||
});
|
||||
}
|
||||
|
||||
@@ -64,27 +64,27 @@ export const rota = new RotaState();
|
||||
export const steps = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Βασικές Ρυθμίσεις",
|
||||
title: "Περίοδος",
|
||||
description: "Καθόρισε την περίοδο και τις αργίες του μήνα."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Ρύθμιση Προσωπικού",
|
||||
title: "Ειδικευόμενοι",
|
||||
description: "Δημιούργησε νέα εγγραφή ειδικευόμενου."
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Προχωρημένες Ρυθμίσεις",
|
||||
title: "Προχωρημένα",
|
||||
description: "Επίλεξε ζευγάρια ατόμων που δεν μπορούν να κάνουν μαζί εφημερία."
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Επισκόπηση Προγράμματος",
|
||||
title: "Επισκόπηση",
|
||||
description: "Έλεγξε το πρόγραμμα με τις υποχρεωτικές υπάρχουσες εφημερίες."
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "Δημιουργία Προγράμματος",
|
||||
title: "Δημιουργία",
|
||||
description: "Τρέξε τον αλγόριθμο ανάθεσης εφημεριών, εξήγαγε τα αποτελέσματα."
|
||||
}
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user