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 import { getIsCoarse } from '$lib/website/context';
9
10 function tryGetIsCoarse(): (() => boolean) | undefined {
11 try {
12 return getIsCoarse();
13 } catch {
14 return undefined;
15 }
16 }
17 const isCoarse = tryGetIsCoarse();
18
19 const colors = {
20 base: 'bg-base-200/50 dark:bg-base-950/50',
21 accent: 'bg-accent-400 dark:bg-accent-500 accent',
22 transparent: ''
23 } as Record<string, string>;
24
25 export type BaseCardProps = {
26 item: Item;
27 controls?: Snippet<[]>;
28 isEditing?: boolean;
29 showOutline?: boolean;
30 locked?: boolean;
31 } & WithElementRef<HTMLAttributes<HTMLDivElement>>;
32
33 let {
34 item,
35 children,
36 ref = $bindable(null),
37 isEditing = false,
38 controls,
39 showOutline,
40 locked = false,
41 class: className,
42 ...rest
43 }: BaseCardProps = $props();
44
45 let color = $derived(getColor(item));
46</script>
47
48<div
49 id={item.id}
50 data-flip-id={item.id}
51 bind:this={ref}
52 draggable={isEditing && !locked && !isCoarse?.()}
53 class={[
54 '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',
55 color ? (colors[color] ?? colors.accent) : colors.base,
56 color !== 'accent' && item.color !== 'base' && item.color !== 'transparent' ? color : '',
57 showOutline ? 'outline-2' : '',
58 className
59 ]}
60 style={`
61 --mx: ${item.mobileX};
62 --my: ${item.mobileY};
63 --mw: ${item.mobileW};
64 --mh: ${item.mobileH};
65 --mm: ${mobileMargin}px;
66
67 --dx: ${item.x};
68 --dy: ${item.y};
69 --dw: ${item.w};
70 --dh: ${item.h};
71 --dm: ${margin}px;
72
73 --columns: ${COLUMNS}`}
74 {...rest}
75>
76 <div
77 class={[
78 'text-base-900 dark:text-base-50 relative isolate h-full w-full overflow-hidden rounded-[23px]',
79 color !== 'base' && color != 'transparent' ? 'light' : ''
80 ]}
81 >
82 {@render children?.()}
83
84 {#if !isEditing && item.cardData.label}
85 <div
86 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"
87 >
88 {item.cardData.label}
89 </div>
90 {/if}
91 </div>
92 {@render controls?.()}
93</div>
94
95<style>
96 .card {
97 translate: calc((var(--mx) / var(--columns)) * 100cqw + var(--mm))
98 calc((var(--my) / var(--columns)) * 100cqw + var(--mm));
99 width: calc((var(--mw) / var(--columns)) * 100cqw - (var(--mm) * 2));
100 height: calc((var(--mh) / var(--columns)) * 100cqw - (var(--mm) * 2));
101 }
102
103 @container grid (width >= 42rem) {
104 .card {
105 translate: calc((var(--dx) / var(--columns)) * 100cqw + var(--dm))
106 calc((var(--dy) / var(--columns)) * 100cqw + var(--dm));
107 width: calc((var(--dw) / var(--columns)) * 100cqw - (var(--dm) * 2));
108 height: calc((var(--dh) / var(--columns)) * 100cqw - (var(--dm) * 2));
109 }
110 }
111</style>