forked from
haetae.tngl.sh/fanfic-atproto
personal fork for experimenting
1---
2import { Info, TriangleAlert, Skull } from "@lucide/astro";
3
4interface Props {
5 id?: string;
6 label: string;
7 icon?: "info" | "warning" | "danger";
8 title?: string;
9 class?: string;
10}
11
12const { id, label, icon, title, class: className, ...rest } = Astro.props;
13---
14<!-- type button needs to be set here, otherwise it doesn't work inside forms -->
15<button
16 type="button"
17 id={`${id}-trigger`}
18 class:list={[
19 "btn btn-xs",
20 icon && ["btn-circle", "btn-ghost"],
21 icon &&
22 (icon === "info") ? "text-info" :
23 (icon === "warning") ? "text-warning" :
24 (icon === "danger") ? "text-error" :
25 "text-base-content",
26 "popover-btn"
27 ]}
28 aria-describedby={id}
29 popovertarget={id}
30>
31 {icon
32 ?
33 <div class="icon" aria-label={label}>
34 {icon &&
35 (icon === "info") ? <Info /> :
36 (icon === "warning") ? <TriangleAlert /> :
37 (icon === "danger") ? <Skull /> :
38 <></>
39 }
40 </div>
41 : <span>{label}</span>
42 }
43</button>
44
45<div
46 {id}
47 class:list={[
48 "popover-content",
49 className,
50 ]}
51 role="tooltip"
52 popover="auto"
53 {...rest}
54>
55 <div class="card-body">
56 {title && (
57 <h3 class="card-title">{title}</h3>
58 )}
59
60 <slot />
61 </div>
62</div>
63
64<style define:vars={{ anchor: `--${id}-anchor` }}>
65 @reference "../assets/styles/global.css";
66
67 .popover-btn {
68 @supports (anchor-name: var(--anchor)) {
69 anchor-name: var(--anchor);
70 }
71 }
72
73 .popover-content {
74 @apply dropdown card mx-0 inset-auto bg-base-100 w-72 shadow;
75
76 @supports (position-anchor: var(--anchor)) and (left: anchor(center)) {
77 position-anchor: var(--anchor);
78 left: anchor(center);
79 transform: translateX(-50%);
80 }
81 }
82</style>
83
84<script>
85 import { computePosition, autoUpdate, shift, flip } from "@floating-ui/dom";
86 const triggers = document.querySelectorAll(".popover-btn");
87
88 triggers.forEach(trigger => {
89 const btn = trigger as HTMLButtonElement;
90 // triggering button will always end with "-trigger"
91 // so slice that from the id
92 const id = btn.id.slice(0, -8);
93 const popover = document.getElementById(`${id}`) as HTMLElement;
94
95 btn.addEventListener("click", (e) => {
96 e.preventDefault();
97 popover.togglePopover();
98 });
99
100 popover.addEventListener("toggle", (e) => {
101 const cleanup = autoUpdate(
102 btn,
103 popover,
104 () => {
105 computePosition(btn, popover, {
106 middleware: [
107 flip(),
108 shift({
109 crossAxis: false,
110 }),
111 ],
112 }).then(({ placement, middlewareData }) => {
113 Object.assign(popover.style, {
114 top: `anchor(${placement})`,
115 ...(placement === "top") && {
116 transform: (middlewareData.shift?.enabled.x)
117 ? `translate(calc(-50% + ${middlewareData.shift.x}px), -100%)`
118 : `translate(-50%, -100%)`,
119 },
120 });
121 });
122 });
123 if (e.newState === "open") {
124 cleanup;
125 } else {
126 cleanup();
127 }
128 });
129 });
130</script>