Skip to content

Commit

Permalink
feat: allow editing social media links separate from other links.
Browse files Browse the repository at this point in the history
  • Loading branch information
zicklag committed Jan 17, 2025
1 parent cd66baf commit c293e0c
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 81 deletions.
10 changes: 1 addition & 9 deletions src/lib/components/editors/LinksEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
import { Handle } from '@rodrigodagostino/svelte-sortable-list';
import { IconHandle } from '@rodrigodagostino/svelte-sortable-list';
import SocialMediaButton from '../social-media/social-media-button.svelte';
import { getFeaturedSocialMediaDetails } from '$lib/utils/social-links';
import FeaturedSocialMediaButton from '../social-media/featured-social-media-button.svelte';
import { debounce } from 'underscore';
let {
Expand Down Expand Up @@ -76,8 +74,6 @@
return new URL(url).host;
} catch (_) {}
}
let featuredLinks = $derived(links.filter((x) => getFeaturedSocialMediaDetails(x.url)));
</script>

<div class="flex flex-col" {...attrs}>
Expand Down Expand Up @@ -124,11 +120,7 @@
<Handle>
<IconHandle />
</Handle>
{#if featuredLinks.includes(link)}
<FeaturedSocialMediaButton url={link.url} />
{:else}
<SocialMediaButton url={link.url} label={link.label || host(link.url)} />
{/if}
<SocialMediaButton url={link.url} label={link.label || host(link.url)} />

<button
class="variant-ghost btn-icon btn-icon-sm"
Expand Down
34 changes: 34 additions & 0 deletions src/lib/components/editors/SocialLinksEditor.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script lang="ts">
import SocialLinkInput from './SocialLinksEditor/SocialLinkInput.svelte';
import { onMount } from 'svelte';
import { getSocialMediaDetails } from '$lib/utils/social-links';
let { links = $bindable() }: { links: { label?: string; url: string }[] } = $props();
let localLinks = $state([]) as typeof links;
onMount(() => {
localLinks = links;
});
$effect(() => {
links = localLinks
.filter((x) => !!x.url)
.map((x) => ({ url: x.url, label: getSocialMediaDetails(x.url).name }));
});
$effect(() => {
const lastLink = localLinks[localLinks.length - 1];
const secondToLastLink = localLinks[localLinks.length - 2];
if (!lastLink || lastLink.url !== '') {
localLinks.push({ url: '' });
} else if (secondToLastLink && secondToLastLink.url === '' && lastLink.url === '') {
localLinks.pop();
}
if (localLinks.slice(0, -1).some((x) => !x.url)) {
localLinks = [...localLinks.filter((x) => !!x.url), localLinks[localLinks.length - 1]];
}
});
</script>

{#each localLinks as link, i (i)}
<SocialLinkInput bind:url={link.url} />
{/each}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts">
import { getSocialMediaDetails } from '$lib/utils/social-links';
import Icon from '@iconify/svelte';
let { url = $bindable() }: { url: string } = $props();
let linkDetails = $derived(getSocialMediaDetails(url));
let input: HTMLInputElement;
export function focus() {
input.focus();
}
</script>

<div>
<div class="input-group input-group-divider grid-cols-[auto_1fr_auto]">
<div class="input-group-shim">
<Icon icon={linkDetails.icon} />
</div>
<input type="text" bind:this={input} placeholder="https://example.com" bind:value={url} />
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<script>
import { getFeaturedSocialMediaDetails, getSocialMediaDetails } from '$lib/utils/social-links';
<script lang="ts">
import { getSocialMediaDetails } from '$lib/utils/social-links';
import Icon from '@iconify/svelte';
export let url;
export let verified = false;
let { url, verified = true }: { url: string; verified: boolean } = $props();
const socialMedia = getSocialMediaDetails(url);
const featuredSocialMedia = getFeaturedSocialMediaDetails(url);
const socialMedia = $derived(getSocialMediaDetails(url));
</script>

<div class="relative">
Expand All @@ -18,11 +16,11 @@
<a
href={url}
target="_blank"
title={featuredSocialMedia?.name || socialMedia.name}
title={socialMedia.name}
class="variant-outline-primary btn btn-icon-sm"
>
<span>
<Icon icon={featuredSocialMedia?.icon || socialMedia.icon} class="h-6 w-6" />
<Icon icon={socialMedia.icon} class="h-6 w-6" />
</span>
</a>
</div>
34 changes: 29 additions & 5 deletions src/lib/leaf/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface Profile {
display_name?: string;
tags: string[];
bio?: string;
social_links: { label?: string; url: string }[];
links: { label?: string; url: string }[];
mastodon_profile?: {
username: string;
Expand Down Expand Up @@ -142,6 +143,27 @@ Each link has an optional label and a URL, which must be a valid URL`)
}
}

export class SocialLinks extends Component {
value: WebLink[];
constructor(links: WebLink[]) {
super();
this.value = links;
}
static componentName(): string {
return 'SocialLinks';
}
static borshSchema(): BorshSchema {
return BorshSchema.Vec(WebLinkSchema);
}
static specification(): Component[] {
return [
new CommonMark(`A list of social links associated to the entity.
These links are to social profiles that represent the same identity as this entity.`)
];
}
}

export class MastodonProfile extends Component {
value: {
username: string;
Expand Down Expand Up @@ -240,14 +262,16 @@ export async function getProfile(link: ExactLink): Promise<Profile | undefined>
WeirdCustomDomain,
MastodonProfile,
WeirdPubpageTheme,
WebLinks
WebLinks,
SocialLinks
);
return (
(ent && {
display_name: ent.get(Name)?.value,
bio: ent.get(Description)?.value,
tags: ent.get(Tags)?.value || [],
// custom_domain: ent.get(WeirdCustomDomain)?.value,
social_links: ent.get(SocialLinks)?.value || [],
links: ent.get(WebLinks)?.value || [],
mastodon_profile: ent.get(MastodonProfile)?.value,
pubpage_theme: ent.get(WeirdPubpageTheme)?.value
Expand All @@ -266,6 +290,7 @@ export async function setRawProfile(link: ExactLink, profile: Profile) {
profile.mastodon_profile ? new MastodonProfile(profile.mastodon_profile) : MastodonProfile,
profile.pubpage_theme ? new WeirdPubpageTheme(profile.pubpage_theme) : WeirdPubpageTheme,
profile.links ? new WebLinks(profile.links) : WebLinks,
profile.social_links ? new SocialLinks(profile.social_links) : SocialLinks,
profile.tags ? new Tags(profile.tags) : Tags
]);
}
Expand Down Expand Up @@ -342,10 +367,9 @@ export async function setProfileById(rauthyId: string, profile: Profile): Promis
// Update the user's verified links
const username = await usernames.getByRauthyId(rauthyId);
if (username) {
await verifiedLinks.verify(
username,
profile.links.map((x) => x.url)
);
await verifiedLinks.verify(username, [
...new Set([...profile.links, ...profile.social_links].map((x) => x.url)).values()
]);
}

await setRawProfile(link, profile);
Expand Down
1 change: 1 addition & 0 deletions src/lib/renderer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export type ProfileData = {
display_name?: string;
bio?: string;
tags?: string[];
social_links?: { url: string; label?: string }[];
links?: { url: string; label?: string }[];
pages?: { slug: string; name?: string }[];
};
Expand Down
5 changes: 5 additions & 0 deletions src/lib/themes/weird.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -3030,6 +3030,11 @@
Weird
</a>
{% if links %}
{% for link in social_links %}
<a rel="me" href="{{link.url}}" target="_blank" class="link">
{{link.label or link.url}}
</a>
{% endfor %}
{% for link in links %}
<a rel="me" href="{{link.url}}" target="_blank" class="link">
{{link.label or link.url}}
Expand Down
6 changes: 5 additions & 1 deletion src/routes/(app)/[username]/+layout.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export const load: LayoutServerLoad = async ({ fetch, params, request, url }) =>
const subspace = await usernames.getSubspace(fullUsername);
if (!subspace) return error(404, `User not found: ${fullUsername}`);

const profile = (await getProfile(subspace_link(subspace, null))) || { tags: [], links: [] };
const profile = (await getProfile(subspace_link(subspace, null))) || {
tags: [],
links: [],
social_links: []
};

const { sessionInfo } = await getSession(fetch, request);
if (sessionInfo && sessionInfo.user_id == (await usernames.getRauthyId(fullUsername))) {
Expand Down
12 changes: 12 additions & 0 deletions src/routes/(app)/[username]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ export const actions = {
link.url = 'https://' + link.url;
}
}
let social_links: { label?: string; url: string }[] = JSON.parse(
data.get('social_links')?.toString() || '{}'
);
for (const link of social_links) {
try {
new URL(link.url);
} catch (_) {
// If it isn't a valid URL, try just prepending `https://` to it.
link.url = 'https://' + link.url;
}
}
let bio = data.get('bio')?.toString() || undefined;
if (bio === '') {
bio = undefined;
Expand Down Expand Up @@ -66,6 +77,7 @@ export const actions = {
display_name,
tags,
links,
social_links,
bio,
mastodon_profile,
pubpage_theme
Expand Down
Loading

0 comments on commit c293e0c

Please sign in to comment.