tangled
alpha
login
or
join now
flo-bit.dev
/
blento
your personal website on atproto - mirror
blento.app
20
fork
atom
overview
issues
pulls
pipelines
more cleanup
Florian
3 weeks ago
2ac245dc
b2bf519d
+143
-66
9 changed files
expand all
collapse all
unified
split
src
lib
cards
BigSocialCard
index.ts
EmbedCard
index.ts
ImageCard
ImageCardSettings.svelte
index.ts
LinkCard
index.ts
LivestreamCard
LivestreamEmbedCard.svelte
index.ts
TextCard
TextCardSettings.svelte
website
EditableWebsite.svelte
+1
-1
src/lib/cards/BigSocialCard/index.ts
···
29
29
const platform = href ? detectPlatform(href) : null;
30
30
if (!href || !platform) return item;
31
31
item.cardData = {
32
32
-
href,
32
32
+
...item.cardData,
33
33
platform,
34
34
color: platformsData[platform].hex
35
35
};
+1
-2
src/lib/cards/EmbedCard/index.ts
···
1
1
import type { CardDefinition } from '../types';
2
2
import CreateEmbedCardModal from './CreateEmbedCardModal.svelte';
3
3
import EmbedCard from './EmbedCard.svelte';
4
4
-
import SidebarItemEmbedCard from './SidebarItemEmbedCard.svelte';
5
4
6
5
export const EmbedCardDefinition = {
7
6
type: 'embed',
8
7
contentComponent: EmbedCard,
9
8
creationModalComponent: CreateEmbedCardModal,
10
10
-
sidebarComponent: SidebarItemEmbedCard,
9
9
+
11
10
createNew: (card) => {
12
11
card.w = 4;
13
12
card.h = 4;
+54
src/lib/cards/ImageCard/ImageCardSettings.svelte
···
1
1
+
<script lang="ts">
2
2
+
import { validateLink } from '$lib/helper';
3
3
+
import type { Item } from '$lib/types';
4
4
+
import { Button, Input, toast } from '@foxui/core';
5
5
+
6
6
+
let { item, onclose }: { item: Item; onclose: () => void } = $props();
7
7
+
8
8
+
let linkValue = $derived(
9
9
+
item.cardData.href?.replace('https://', '').replace('http://', '') ?? ''
10
10
+
);
11
11
+
12
12
+
function updateLink() {
13
13
+
if (!linkValue.trim()) {
14
14
+
item.cardData.href = '';
15
15
+
item.cardData.domain = '';
16
16
+
}
17
17
+
18
18
+
let link = validateLink(linkValue);
19
19
+
if (!link) {
20
20
+
toast.error('Invalid link');
21
21
+
return;
22
22
+
}
23
23
+
24
24
+
item.cardData.href = link;
25
25
+
item.cardData.domain = new URL(link).hostname;
26
26
+
27
27
+
onclose?.();
28
28
+
}
29
29
+
</script>
30
30
+
31
31
+
<Input
32
32
+
spellcheck={false}
33
33
+
type="url"
34
34
+
bind:value={linkValue}
35
35
+
onkeydown={(event) => {
36
36
+
if (event.code === 'Enter') {
37
37
+
updateLink();
38
38
+
event.preventDefault();
39
39
+
}
40
40
+
}}
41
41
+
placeholder="Enter link"
42
42
+
/>
43
43
+
<Button onclick={updateLink} size="icon"
44
44
+
><svg
45
45
+
xmlns="http://www.w3.org/2000/svg"
46
46
+
fill="none"
47
47
+
viewBox="0 0 24 24"
48
48
+
stroke-width="1.5"
49
49
+
stroke="currentColor"
50
50
+
class="size-6"
51
51
+
>
52
52
+
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" />
53
53
+
</svg>
54
54
+
</Button>
+3
-1
src/lib/cards/ImageCard/index.ts
···
1
1
import { uploadBlob } from '$lib/oauth/utils';
2
2
import type { CardDefinition } from '../types';
3
3
import ImageCard from './ImageCard.svelte';
4
4
+
import ImageCardSettings from './ImageCardSettings.svelte';
4
5
5
6
export const ImageCardDefinition = {
6
7
type: 'image',
···
27
28
}
28
29
29
30
return item;
30
30
-
}
31
31
+
},
32
32
+
settingsComponent: ImageCardSettings
31
33
} as CardDefinition & { type: 'image' };
+1
-1
src/lib/cards/LinkCard/index.ts
···
20
20
if (!href) return item;
21
21
22
22
item.cardData = {
23
23
-
href,
23
23
+
...item.cardData,
24
24
hasFetched: false
25
25
};
26
26
return item;
+3
-8
src/lib/cards/LivestreamCard/LivestreamEmbedCard.svelte
···
1
1
<script lang="ts">
2
2
import type { ContentComponentProps } from '../types';
3
3
4
4
-
let {
5
5
-
item,
6
6
-
sandbox
7
7
-
}: ContentComponentProps & {
8
8
-
sandbox: string;
9
9
-
} = $props();
4
4
+
let { item }: ContentComponentProps = $props();
10
5
11
6
// svelte-ignore state_referenced_locally
12
12
-
let domain = new URL(item.cardData.href).hostname;
7
7
+
let domain = new URL(item.cardData.embed).hostname;
13
8
</script>
14
9
15
10
{#if domain === 'stream.place'}
16
11
<iframe
17
17
-
src={item.cardData.href}
12
12
+
src={item.cardData.embed}
18
13
sandbox="allow-scripts allow-same-origin"
19
14
referrerpolicy="no-referrer"
20
15
class="absolute inset-0 h-full w-full"
+28
-4
src/lib/cards/LivestreamCard/index.ts
···
4
4
import type { CardDefinition } from '../types';
5
5
import LivestreamCard from './LivestreamCard.svelte';
6
6
import LivestreamEmbedCard from './LivestreamEmbedCard.svelte';
7
7
-
import SidebarItemEmbedLivestreamCard from './SidebarItemEmbedLivestreamCard.svelte';
8
7
import SidebarItemLivestreamCard from './SidebarItemLivestreamCard.svelte';
9
8
10
9
export const LivestreamCardDefitition = {
···
16
15
card.h = 4;
17
16
card.mobileH = 8;
18
17
card.mobileW = 8;
18
18
+
19
19
+
card.cardType = 'latestLivestream';
19
20
},
20
21
loadData: async (items, { did }) => {
21
22
const records = await listRecords({ did, collection: 'place.stream.livestream', limit: 3 });
···
63
64
}
64
65
65
66
return latestLivestream;
66
66
-
}
67
67
+
},
68
68
+
69
69
+
onUrlHandler: (url, item) => {
70
70
+
console.log(url, 'https://stream.place/' + client.profile?.handle);
71
71
+
if (url === 'https://stream.place/' + client.profile?.handle) {
72
72
+
item.w = 4;
73
73
+
item.h = 4;
74
74
+
item.mobileH = 8;
75
75
+
item.mobileW = 8;
76
76
+
item.cardData.href = 'https://stream.place/' + client.profile?.handle;
77
77
+
return item;
78
78
+
}
79
79
+
},
80
80
+
81
81
+
canChange: (item) => item.cardData.href === 'https://stream.place/' + client.profile?.handle,
82
82
+
83
83
+
urlHandlerPriority: 5,
84
84
+
85
85
+
name: 'stream.place Card'
67
86
} as CardDefinition & { type: 'latestLivestream' };
68
87
69
88
export const LivestreamEmbedCardDefitition = {
70
89
type: 'livestreamEmbed',
71
90
contentComponent: LivestreamEmbedCard,
72
72
-
sidebarComponent: SidebarItemEmbedLivestreamCard,
73
91
createNew: (card) => {
74
92
card.w = 4;
75
93
card.h = 2;
···
77
95
card.mobileH = 4;
78
96
79
97
card.cardData = {
80
80
-
href: 'https://stream.place/embed/' + client.profile?.handle
98
98
+
href: 'https://stream.place/' + client.profile?.handle,
99
99
+
embed: 'https://stream.place/embed/' + client.profile?.handle
81
100
};
82
101
}
102
102
+
// canChange: (item) => item.cardData.href === 'https://stream.place/' + client.profile?.handle,
103
103
+
104
104
+
// change: (item) => {
105
105
+
// item.cardData.embed = 'https://stream.place/embed/' + client.profile?.handle;
106
106
+
// },
83
107
} as CardDefinition & { type: 'livestreamEmbed' };
+48
-46
src/lib/cards/TextCard/TextCardSettings.svelte
···
9
9
</script>
10
10
11
11
<div class="flex flex-col gap-2">
12
12
-
<ToggleGroup
13
13
-
type="single"
14
14
-
bind:value={
15
15
-
() => {
16
16
-
return item.cardData.textAlign ?? 'left';
17
17
-
},
18
18
-
(value) => {
19
19
-
if (!value) return;
20
20
-
item.cardData.textAlign = value;
21
21
-
}
22
22
-
}
23
23
-
>
24
24
-
<ToggleGroupItem size="sm" value="left" class={classes}
25
25
-
><svg
26
26
-
xmlns="http://www.w3.org/2000/svg"
27
27
-
viewBox="0 0 24 24"
28
28
-
fill="none"
29
29
-
stroke="currentColor"
30
30
-
stroke-width="2"
31
31
-
stroke-linecap="round"
32
32
-
stroke-linejoin="round"><path d="M21 5H3" /><path d="M15 12H3" /><path d="M17 19H3" /></svg
33
33
-
></ToggleGroupItem
34
34
-
>
35
35
-
<ToggleGroupItem size="sm" value="center" class={classes}
36
36
-
><svg
37
37
-
xmlns="http://www.w3.org/2000/svg"
38
38
-
viewBox="0 0 24 24"
39
39
-
fill="none"
40
40
-
stroke="currentColor"
41
41
-
stroke-width="2"
42
42
-
stroke-linecap="round"
43
43
-
stroke-linejoin="round"><path d="M21 5H3" /><path d="M17 12H7" /><path d="M19 19H5" /></svg
44
44
-
></ToggleGroupItem
45
45
-
>
46
46
-
<ToggleGroupItem size="sm" value="right" class={classes}
47
47
-
><svg
48
48
-
xmlns="http://www.w3.org/2000/svg"
49
49
-
viewBox="0 0 24 24"
50
50
-
fill="none"
51
51
-
stroke="currentColor"
52
52
-
stroke-width="2"
53
53
-
stroke-linecap="round"
54
54
-
stroke-linejoin="round"><path d="M21 5H3" /><path d="M21 12H9" /><path d="M21 19H7" /></svg
55
55
-
></ToggleGroupItem
56
56
-
>
57
57
-
</ToggleGroup>
58
12
59
13
<ToggleGroup
60
14
type="single"
···
119
73
></ToggleGroupItem
120
74
>
121
75
</ToggleGroup>
76
76
+
77
77
+
<ToggleGroup
78
78
+
type="single"
79
79
+
bind:value={
80
80
+
() => {
81
81
+
return item.cardData.textAlign ?? 'left';
82
82
+
},
83
83
+
(value) => {
84
84
+
if (!value) return;
85
85
+
item.cardData.textAlign = value;
86
86
+
}
87
87
+
}
88
88
+
>
89
89
+
<ToggleGroupItem size="sm" value="left" class={classes}
90
90
+
><svg
91
91
+
xmlns="http://www.w3.org/2000/svg"
92
92
+
viewBox="0 0 24 24"
93
93
+
fill="none"
94
94
+
stroke="currentColor"
95
95
+
stroke-width="2"
96
96
+
stroke-linecap="round"
97
97
+
stroke-linejoin="round"><path d="M21 5H3" /><path d="M15 12H3" /><path d="M17 19H3" /></svg
98
98
+
></ToggleGroupItem
99
99
+
>
100
100
+
<ToggleGroupItem size="sm" value="center" class={classes}
101
101
+
><svg
102
102
+
xmlns="http://www.w3.org/2000/svg"
103
103
+
viewBox="0 0 24 24"
104
104
+
fill="none"
105
105
+
stroke="currentColor"
106
106
+
stroke-width="2"
107
107
+
stroke-linecap="round"
108
108
+
stroke-linejoin="round"><path d="M21 5H3" /><path d="M17 12H7" /><path d="M19 19H5" /></svg
109
109
+
></ToggleGroupItem
110
110
+
>
111
111
+
<ToggleGroupItem size="sm" value="right" class={classes}
112
112
+
><svg
113
113
+
xmlns="http://www.w3.org/2000/svg"
114
114
+
viewBox="0 0 24 24"
115
115
+
fill="none"
116
116
+
stroke="currentColor"
117
117
+
stroke-width="2"
118
118
+
stroke-linecap="round"
119
119
+
stroke-linejoin="round"><path d="M21 5H3" /><path d="M21 12H9" /><path d="M21 19H7" /></svg
120
120
+
></ToggleGroupItem
121
121
+
>
122
122
+
</ToggleGroup>
123
123
+
122
124
123
125
<div>
124
126
<Button
+4
-3
src/lib/website/EditableWebsite.svelte
···
97
97
}
98
98
99
99
let item = createEmptyCard(data.page);
100
100
+
item.cardType = type;
100
101
101
102
item.cardData = cardData ?? {};
102
103
···
319
320
const objectUrl = URL.createObjectURL(compressedFile);
320
321
321
322
let item = createEmptyCard(data.page);
322
322
-
323
323
+
323
324
item.cardType = 'image';
324
325
item.cardData = {
325
325
-
blob: compressedFile,
326
326
-
objectUrl
326
326
+
blob: compressedFile,
327
327
+
objectUrl
327
328
};
328
329
329
330
// If grid position is provided