your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import { getImage } from '$lib/helper';
3 import { getDidContext } from '$lib/website/context';
4 import type { ContentComponentProps } from '../../types';
5 import { qrOverlay } from '$lib/components/qr/qrOverlay.svelte';
6
7 let { item, isEditing }: ContentComponentProps = $props();
8
9 let faviconHasError = $state(false);
10
11 let did = getDidContext();
12</script>
13
14{#if item.cardData.showBackgroundImage && item.cardData.image}
15 <div class="link-card relative flex h-full flex-col justify-end p-4">
16 <img
17 class="absolute inset-0 -z-10 size-full object-cover"
18 src={getImage(item.cardData, did)}
19 alt=""
20 />
21 <div
22 class="from-base-50/90 via-base-50/40 dark:from-base-950/90 dark:via-base-950/40 absolute inset-0 -z-10 bg-linear-to-t to-transparent"
23 ></div>
24 <div class="text-accent-600 dark:text-accent-400 text-xs font-semibold">
25 {item.cardData.domain}
26 </div>
27 <div class="link-title text-base-900 dark:text-base-50 text-lg font-bold">
28 {item.cardData.title}
29 </div>
30 {#if item.cardData.href && !isEditing}
31 <a
32 href={item.cardData.href}
33 class="absolute inset-0 h-full w-full"
34 target="_blank"
35 rel="noopener noreferrer"
36 use:qrOverlay={{
37 context: {
38 title: item.cardData.title
39 }
40 }}
41 >
42 <span class="sr-only">
43 {item.cardData.hrefText ?? 'Learn more'}
44 </span>
45
46 <div
47 class="bg-base-800/30 border-base-900/30 absolute top-2 right-2 rounded-full border p-1 text-white opacity-50 backdrop-blur-lg group-focus-within:opacity-100 group-hover:opacity-100"
48 >
49 <svg
50 xmlns="http://www.w3.org/2000/svg"
51 fill="none"
52 viewBox="0 0 24 24"
53 stroke-width="2.5"
54 stroke="currentColor"
55 class="size-4"
56 >
57 <path
58 stroke-linecap="round"
59 stroke-linejoin="round"
60 d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25"
61 />
62 </svg>
63 </div>
64 </a>
65 {/if}
66 </div>
67{:else}
68 <div class="link-card flex h-full flex-col p-4">
69 <div class="link-content min-h-0">
70 <div
71 class="bg-base-100 border-base-300 accent:bg-accent-100/50 accent:border-accent-200 dark:border-base-800 dark:bg-base-900 mb-2 inline-flex size-8 items-center justify-center rounded-xl border"
72 >
73 {#if item.cardData.favicon && !faviconHasError}
74 <img
75 class="size-6 rounded-lg object-cover"
76 onerror={() => (faviconHasError = true)}
77 src={getImage(item.cardData, did, 'favicon')}
78 alt=""
79 />
80 {:else}
81 <svg
82 xmlns="http://www.w3.org/2000/svg"
83 fill="none"
84 viewBox="0 0 24 24"
85 stroke-width="1.5"
86 stroke="currentColor"
87 class="size-4"
88 >
89 <path
90 stroke-linecap="round"
91 stroke-linejoin="round"
92 d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244"
93 />
94 </svg>
95 {/if}
96 </div>
97 <div class="link-title text-base-900 dark:text-base-50 text-lg font-bold">
98 {item.cardData.title}
99 </div>
100 <!-- <div class="text-base-800 dark:text-base-100 mt-2 text-xs">{item.cardData.description}</div> -->
101 <div
102 class="text-accent-600 accent:text-accent-950 dark:text-accent-400 mt-2 text-xs font-semibold"
103 >
104 {item.cardData.domain}
105 </div>
106 </div>
107
108 {#if item.cardData.image}
109 <div class="link-preview-wrap mt-auto">
110 <img
111 class="link-preview mb-2 aspect-2/1 w-full rounded-xl object-cover opacity-100 transition-opacity duration-100 starting:opacity-0"
112 src={getImage(item.cardData, did)}
113 alt=""
114 />
115 </div>
116 {/if}
117 {#if item.cardData.href && !isEditing}
118 <a
119 href={item.cardData.href}
120 class="absolute inset-0 h-full w-full"
121 target="_blank"
122 rel="noopener noreferrer"
123 use:qrOverlay={{
124 context: {
125 title: item.cardData.title
126 }
127 }}
128 >
129 <span class="sr-only">
130 {item.cardData.hrefText ?? 'Learn more'}
131 </span>
132
133 <div
134 class="bg-base-800/30 border-base-900/30 absolute top-2 right-2 rounded-full border p-1 text-white opacity-50 backdrop-blur-lg group-focus-within:opacity-100 group-hover:opacity-100"
135 >
136 <svg
137 xmlns="http://www.w3.org/2000/svg"
138 fill="none"
139 viewBox="0 0 24 24"
140 stroke-width="2.5"
141 stroke="currentColor"
142 class="size-4"
143 >
144 <path
145 stroke-linecap="round"
146 stroke-linejoin="round"
147 d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25"
148 />
149 </svg>
150 </div>
151 </a>
152 {/if}
153 </div>
154{/if}
155
156<style>
157 .link-title {
158 display: -webkit-box;
159 line-clamp: 2;
160 overflow: hidden;
161 -webkit-box-orient: vertical;
162 -webkit-line-clamp: 2;
163 }
164
165 .link-preview {
166 display: none;
167 width: 100%;
168 object-fit: cover;
169 }
170
171 .link-preview-wrap {
172 display: none;
173 padding-top: 1rem;
174 }
175
176 @container card (height >= 18rem) {
177 .link-title {
178 display: block;
179 line-clamp: unset;
180 overflow: visible;
181 -webkit-line-clamp: unset;
182 }
183
184 .link-preview-wrap,
185 .link-preview {
186 display: block;
187 }
188 }
189
190 @container card (height >= 18rem) and (height < 22rem) {
191 .link-content {
192 padding-bottom: 1rem;
193 }
194
195 .link-preview-wrap {
196 padding-top: 0;
197 }
198
199 .link-preview {
200 aspect-ratio: 2.6 / 1;
201 max-height: 4.5rem;
202 }
203 }
204
205 @container card (height >= 22rem) {
206 .link-content {
207 padding-bottom: 0.5rem;
208 }
209
210 .link-preview-wrap {
211 padding-top: 0;
212 }
213
214 .link-preview {
215 aspect-ratio: 2 / 1;
216 max-height: none;
217 }
218 }
219</style>