-
-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
53 changed files
with
1,647 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
apps/frontend/src/lib/components/blocks/calendar-view/calendar-date-remove-button.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<script lang="ts"> | ||
import { Trash2Icon } from "lucide-svelte" | ||
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter" | ||
import { type RecordDO, CalendarView, DateFieldValue, FieldIdVo } from "@undb/table" | ||
import { getRecordsStore } from "$lib/store/records.store" | ||
import { getTable } from "$lib/store/table.store" | ||
import { trpc } from "$lib/trpc/client" | ||
import { createMutation } from "@tanstack/svelte-query" | ||
import { useQueryClient } from "@tanstack/svelte-query" | ||
import { cn } from "$lib/utils" | ||
import { monthStore } from "$lib/store/calendar.store" | ||
export let view: CalendarView | ||
const store = getRecordsStore() | ||
const t = getTable() | ||
let fieldId = view.field.into(undefined) | ||
let field = fieldId ? $t.schema.getFieldById(new FieldIdVo(fieldId)).into(undefined) : undefined | ||
const updateRecord = createMutation({ | ||
mutationFn: trpc.record.update.mutate, | ||
}) | ||
const client = useQueryClient() | ||
let isDraggedOver = false | ||
function setupDropTarget(node: HTMLElement) { | ||
dropTargetForElements({ | ||
element: node, | ||
getData(e) { | ||
return { | ||
type: "calendar-date-drop", | ||
} | ||
}, | ||
onDragEnter(e) { | ||
isDraggedOver = true | ||
}, | ||
onDragLeave(e) { | ||
isDraggedOver = false | ||
}, | ||
async onDrop(args) { | ||
if (!field) return | ||
const data = args.source.data | ||
const type = data.type | ||
if (type !== "calendar-date-drag") { | ||
return | ||
} | ||
const record = data.record as RecordDO | ||
record.values.setValue(field.id, new DateFieldValue(null)) | ||
store.setRecord(record) | ||
await $updateRecord.mutateAsync({ | ||
tableId: $t.id.value, | ||
id: record.id.value, | ||
values: { | ||
[field.id.value]: null, | ||
}, | ||
}) | ||
await client.invalidateQueries({ | ||
queryKey: ["records", $t?.id.value, view.id.value], | ||
}) | ||
}, | ||
}) | ||
} | ||
</script> | ||
|
||
<button use:setupDropTarget class={cn("hidden transition-opacity", $monthStore.isDragging && "block")}> | ||
<Trash2Icon class={cn("size-10 text-gray-600", isDraggedOver && "text-red-600")} /> | ||
</button> |
101 changes: 101 additions & 0 deletions
101
apps/frontend/src/lib/components/blocks/calendar-view/calendar-field-form.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
<script lang="ts"> | ||
import { Button } from "$lib/components/ui/button/index.js" | ||
import { getTable } from "$lib/store/table.store" | ||
import { updateCalendarViewDTO, type CalendarView } from "@undb/table" | ||
import FieldPicker from "../field-picker/field-picker.svelte" | ||
import { defaults, superForm } from "sveltekit-superforms" | ||
import { zodClient } from "sveltekit-superforms/adapters" | ||
import CreateFieldButton from "../create-field/create-field-button.svelte" | ||
import { trpc } from "$lib/trpc/client" | ||
import { createMutation } from "@tanstack/svelte-query" | ||
import { toast } from "svelte-sonner" | ||
import { invalidate } from "$app/navigation" | ||
import { hasPermission } from "$lib/store/space-member.store" | ||
import { CircleCheckBigIcon } from "lucide-svelte" | ||
export let readonly = false | ||
const table = getTable() | ||
$: fields = $table.schema.getCalendarFields() | ||
export let view: CalendarView | ||
const form = superForm( | ||
defaults( | ||
{ | ||
tableId: $table.id.value, | ||
viewId: view.id.value, | ||
type: "calendar", | ||
name: view.name.value, | ||
calendar: view.calendar.unwrapOrElse(() => ({ field: undefined })), | ||
}, | ||
zodClient(updateCalendarViewDTO), | ||
), | ||
{ | ||
SPA: true, | ||
dataType: "json", | ||
validators: zodClient(updateCalendarViewDTO), | ||
resetForm: false, | ||
invalidateAll: false, | ||
onUpdate(event) { | ||
if (!event.form.valid) return | ||
$updateViewMutation.mutate(event.form.data) | ||
}, | ||
}, | ||
) | ||
const { enhance, form: formData } = form | ||
const updateViewMutation = createMutation({ | ||
mutationFn: trpc.table.view.update.mutate, | ||
mutationKey: ["updateView"], | ||
async onSuccess(data, variables, context) { | ||
toast.success("View updated") | ||
await invalidate(`undb:table:${$table.id.value}`) | ||
}, | ||
}) | ||
</script> | ||
|
||
<div class="space-y-2"> | ||
<form id="select-calendar-field-form" class="space-y-2" use:enhance> | ||
<div class="grid w-full items-center gap-4"> | ||
<div class="flex flex-col space-y-1.5"> | ||
<FieldPicker | ||
disabled={readonly} | ||
placeholder="Select a select type field to group calendar lanes" | ||
value={$formData.calendar?.field} | ||
onValueChange={(field) => { | ||
if ($formData.calendar) { | ||
$formData.calendar.field = field | ||
} else { | ||
$formData.calendar = { field } | ||
} | ||
}} | ||
filter={(f) => fields.map((f) => f.id.value).includes(f.id)} | ||
/> | ||
</div> | ||
</div> | ||
</form> | ||
|
||
{#if !readonly && $hasPermission("field:update")} | ||
<CreateFieldButton class="w-full" variant="secondary" /> | ||
{/if} | ||
|
||
{#if !readonly} | ||
<div class="flex w-full justify-end"> | ||
<Button | ||
variant="outline" | ||
size="sm" | ||
class="w-full" | ||
type="submit" | ||
form="select-calendar-field-form" | ||
disabled={readonly} | ||
> | ||
<CircleCheckBigIcon class="mr-2 size-4" /> | ||
Confirm | ||
</Button> | ||
</div> | ||
{/if} | ||
</div> |
43 changes: 43 additions & 0 deletions
43
apps/frontend/src/lib/components/blocks/calendar-view/calendar-option-button.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<script lang="ts"> | ||
import { Button } from "$lib/components/ui/button" | ||
import { CalendarIcon } from "lucide-svelte" | ||
import * as Dropdown from "$lib/components/ui/dropdown-menu" | ||
import { FieldIdVo, type CalendarView } from "@undb/table" | ||
import CalendarFieldForm from "./calendar-field-form.svelte" | ||
import { getTable } from "$lib/store/table.store" | ||
import FieldIcon from "../field-icon/field-icon.svelte" | ||
const table = getTable() | ||
export let view: CalendarView | ||
export let readonly = false | ||
let fieldId = view.field.into(undefined) | ||
let field = fieldId ? $table.schema.getFieldById(new FieldIdVo(fieldId)).into(undefined) : undefined | ||
</script> | ||
|
||
<Dropdown.Root> | ||
<Dropdown.Trigger asChild let:builder> | ||
<Button variant="ghost" size="sm" class="gap-1" builders={[builder]} {...$$restProps}> | ||
<CalendarIcon class="text-muted-foreground mr-2 h-4 w-4 font-semibold" /> | ||
Calendar | ||
{#if field} | ||
<span>by</span> | ||
<span class="inline-flex items-center gap-1 rounded-sm bg-gray-100 px-1.5 py-0.5"> | ||
<FieldIcon type={field.type} {field} class="size-3 text-gray-700" /> | ||
{field.name.value} | ||
</span> | ||
{/if} | ||
</Button> | ||
</Dropdown.Trigger> | ||
<Dropdown.Content class="w-[400px] p-2"> | ||
<Dropdown.Label> | ||
{#if !readonly} | ||
Update calendar view | ||
{:else} | ||
Calendar view | ||
{/if} | ||
</Dropdown.Label> | ||
<CalendarFieldForm {view} {readonly} /> | ||
</Dropdown.Content> | ||
</Dropdown.Root> |
25 changes: 25 additions & 0 deletions
25
.../frontend/src/lib/components/blocks/calendar-view/calendar-view-mini-month-control.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<script lang="ts"> | ||
import Button from "$lib/components/ui/button/button.svelte" | ||
import * as Popover from "$lib/components/ui/popover" | ||
import { monthStore } from "$lib/store/calendar.store" | ||
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-svelte" | ||
import CalendarViewMiniMonth from "./calendar-view-mini-month.svelte" | ||
import { format } from "date-fns" | ||
</script> | ||
|
||
<Button variant="secondary" size="xs" on:click={() => monthStore.prevMonth()}> | ||
<ChevronLeftIcon class="size-3 font-semibold text-gray-500" /> | ||
</Button> | ||
<Popover.Root> | ||
<Popover.Trigger> | ||
<Button variant="secondary" size="xs"> | ||
{format($monthStore.currentDate, "yyyy-MM")} | ||
</Button> | ||
</Popover.Trigger> | ||
<Popover.Content class="px-0 py-2"> | ||
<CalendarViewMiniMonth /> | ||
</Popover.Content> | ||
</Popover.Root> | ||
<Button variant="secondary" size="xs" on:click={() => monthStore.nextMonth()}> | ||
<ChevronRightIcon class="size-3 font-semibold text-gray-500" /> | ||
</Button> |
41 changes: 41 additions & 0 deletions
41
apps/frontend/src/lib/components/blocks/calendar-view/calendar-view-mini-month.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<script lang="ts"> | ||
import { Button } from "$lib/components/ui/button" | ||
import { monthStore } from "$lib/store/calendar.store" | ||
import { cn } from "$lib/utils" | ||
import { format } from "date-fns" | ||
import { getMonth } from "date-fns/getMonth" | ||
import { isSameMonth } from "date-fns/isSameMonth" | ||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-svelte" | ||
const currentYear = monthStore.currentYear | ||
const currentMonth = monthStore.currentMonth | ||
</script> | ||
|
||
<div class="flex w-full flex-col"> | ||
<div class="flex items-center px-2 py-1"> | ||
<Button variant="ghost" size="icon" on:click={() => monthStore.prevYear()}> | ||
<ChevronLeftIcon class="size-3 text-gray-500" /> | ||
</Button> | ||
<span class="flex-1 text-center text-sm font-medium">{$currentYear}</span> | ||
<Button variant="ghost" size="icon" on:click={() => monthStore.nextYear()}> | ||
<ChevronRightIcon class="size-3 text-gray-500" /> | ||
</Button> | ||
</div> | ||
<div class="grid grid-cols-4 gap-1.5 px-1.5 py-1"> | ||
{#each Array.from({ length: 12 }).map((_, index) => index + 1) as month} | ||
{@const date = new Date($currentYear, month - 1, 1)} | ||
{@const isCurrentMonth = $currentMonth === getMonth(date) + 1} | ||
{@const isNow = isSameMonth(date, new Date())} | ||
<button | ||
class={cn( | ||
"p-2 text-sm hover:bg-gray-100", | ||
isCurrentMonth && "bg-gray-200 font-semibold", | ||
isNow && !isCurrentMonth && "font-semibold text-blue-500", | ||
)} | ||
on:click={() => monthStore.setMonth(date)} | ||
> | ||
{format(date, "MMM")} | ||
</button> | ||
{/each} | ||
</div> | ||
</div> |
Oops, something went wrong.