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