your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import { COLUMNS, margin, mobileMargin } from '$lib';
3 import type { Item } from '$lib/types';
4 import type { WithElementRef } from 'bits-ui';
5 import type { Snippet } from 'svelte';
6 import type { HTMLAttributes } from 'svelte/elements';
7 import { getColor } from '..';
8
9 const colors = {
10 base: 'bg-base-200/50 dark:bg-base-950/50',
11 accent: 'bg-accent-400 dark:bg-accent-500 accent',
12 transparent: ''
13 } as Record<string, string>;
14
15 export type BaseCardProps = {
16 item: Item;
17 controls?: Snippet<[]>;
18 isEditing?: boolean;
19 showOutline?: boolean;
20 locked?: boolean;
21 } & WithElementRef<HTMLAttributes<HTMLDivElement>>;
22
23 let {
24 item,
25 children,
26 ref = $bindable(null),
27 isEditing = false,
28 controls,
29 showOutline,
30 locked = false,
31 class: className,
32 ...rest
33 }: BaseCardProps = $props();
34
35 let color = $derived(getColor(item));
36</script>
37
38<div
39 id={item.id}
40 data-flip-id={item.id}
41 bind:this={ref}
42 draggable={isEditing && !locked}
43 class={[
44 'card group/card selection:bg-accent-600/50 focus-within:outline-accent-500 @container/card absolute isolate z-0 rounded-3xl outline-offset-2 transition-all duration-200 focus-within:outline-2',
45 color ? (colors[color] ?? colors.accent) : colors.base,
46 color !== 'accent' && item.color !== 'base' && item.color !== 'transparent' ? color : '',
47 showOutline ? 'outline-2' : '',
48 className
49 ]}
50 style={`
51 --mx: ${item.mobileX};
52 --my: ${item.mobileY};
53 --mw: ${item.mobileW};
54 --mh: ${item.mobileH};
55 --mm: ${mobileMargin}px;
56
57 --dx: ${item.x};
58 --dy: ${item.y};
59 --dw: ${item.w};
60 --dh: ${item.h};
61 --dm: ${margin}px;
62
63 --columns: ${COLUMNS}`}
64 {...rest}
65>
66 <div
67 class={[
68 'text-base-900 dark:text-base-50 relative isolate h-full w-full overflow-hidden rounded-[23px]',
69 color !== 'base' && color != 'transparent' ? 'light' : ''
70 ]}
71 >
72 {@render children?.()}
73
74 {#if !isEditing && item.cardData.label}
75 <div
76 class="text-base-900 dark:text-base-50 bg-base-200/50 dark:bg-base-900/50 absolute top-2 left-2 z-30 max-w-[calc(100%-1rem)] rounded-xl p-1 px-2 text-base font-semibold backdrop-blur-md"
77 >
78 {item.cardData.label}
79 </div>
80 {/if}
81 </div>
82 {@render controls?.()}
83</div>
84
85<style>
86 .card {
87 translate: calc((var(--mx) / var(--columns)) * 100cqw + var(--mm))
88 calc((var(--my) / var(--columns)) * 100cqw + var(--mm));
89 width: calc((var(--mw) / var(--columns)) * 100cqw - (var(--mm) * 2));
90 height: calc((var(--mh) / var(--columns)) * 100cqw - (var(--mm) * 2));
91 }
92
93 @container grid (width >= 42rem) {
94 .card {
95 translate: calc((var(--dx) / var(--columns)) * 100cqw + var(--dm))
96 calc((var(--dy) / var(--columns)) * 100cqw + var(--dm));
97 width: calc((var(--dw) / var(--columns)) * 100cqw - (var(--dm) * 2));
98 height: calc((var(--dh) / var(--columns)) * 100cqw - (var(--dm) * 2));
99 }
100 }
101</style>