Skip to content

Commit

Permalink
Add guild
Browse files Browse the repository at this point in the history
  • Loading branch information
MacFJA committed Jul 6, 2024
1 parent 9c4aeae commit 3b897e1
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 60 deletions.
3 changes: 2 additions & 1 deletion packages/service/src/collector.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ComposedService, type ContentData, type ServiceMetadata } from "./services/abstract.js";
import { ArticleService } from "./services/article-service.js";
import { GuildService } from "./services/guild-service.js";
import { PackageService } from "./services/package-service.js";
import { type ConnectedService, SocietyStatsService } from "./services/society-stats-service.js";
import { VideoService } from "./services/video-service.js";
Expand All @@ -8,7 +9,7 @@ import { VideoService } from "./services/video-service.js";
export class CollectorService extends ComposedService<any> {
private readonly stats = new SocietyStatsService();
constructor(private userService: ConnectedService) {
super([new VideoService(), new PackageService(), new ArticleService()]);
super([new VideoService(), new PackageService(), new ArticleService(), new GuildService()]);
}

async getInformation(metadata: ServiceMetadata): Promise<ContentData & StatsData & Record<string, unknown>> {
Expand Down
30 changes: 18 additions & 12 deletions packages/service/src/components/content.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<script lang="ts">
// biome-ignore lint/correctness/noUnusedImports: Used in Markup
import { formatDistanceToNow } from "date-fns/formatDistanceToNow";
// biome-ignore lint/correctness/noUnusedImports: Used in Markup
import SvelteMarkdown from "svelte-markdown";
export let type: string;
export let author: string;
export let lastUpdate: string;
export let lastUpdate: string | undefined;
export let views: number;
export let liked = false;
export let likes: number;
Expand All @@ -20,8 +22,8 @@ export let connected = false;
<div>
<strong>{type}</strong>
posted by {author}
&bull;
{formatDistanceToNow(lastUpdate ?? (new Date().toISOString()))}
{#if lastUpdate}&bull;
{formatDistanceToNow(lastUpdate ?? (new Date().toISOString()))}{/if}
&bull;
<span>{views}
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand Down Expand Up @@ -51,17 +53,21 @@ export let connected = false;
{/if}
</header>
<h3>{name}</h3>
<p>{description}</p>
<SvelteMarkdown source={description} />
<section><slot></slot></section>
<footer>
<ul>
{#each tags as tag}
<li>#️ {tag}</li>
{/each}
</ul>
<aside>
{formatDistanceToNow(lastUpdate ?? Date.now())}
</aside>
{#if tags.length}
<ul>
{#each tags as tag}
<li>#️ {tag}</li>
{/each}
</ul>
{/if}
{#if lastUpdate}
<aside>
{formatDistanceToNow(lastUpdate ?? Date.now())}
</aside>
{/if}
</footer>
</article>

Expand Down
39 changes: 39 additions & 0 deletions packages/service/src/components/guild.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script lang="ts">
// biome-ignore lint/correctness/noUnusedImports: Used in Markup
import Content from "./content.svelte";
export let author: string;
export let lastUpdate: string;
export let views: number;
export let liked = false;
export let likes: number;
export let saved = false;
export let name: string;
export let cover: string;
export let members: number;
export let description: string;
export let tags: Array<string> = [];
export let connected = false;
</script>

<Content {...$$props} type="Guild">
{#if cover}
<figure>
<img src={cover}/>
</figure>
{/if}
<strong>{members}</strong> Members
</Content>

<style>
figure {
margin: 0;
padding: 0;
}
figure img {
width: 600px;
height: 300px;
border-radius: 8px;
}
</style>
2 changes: 1 addition & 1 deletion packages/service/src/components/package.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export let tags: Array<string> = [];
export let connected = false;
</script>

<Content {...$$props}>
<Content {...$$props} type="Package">
{#if cover}
<figure>
<img src={cover}/>
Expand Down
2 changes: 1 addition & 1 deletion packages/service/src/components/recipe.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export let tags: Array<string> = [];
export let connected = false;
</script>

<Content type="Recipe" {...$$props}>
<Content {...$$props} type="Recipe">
<SvelteMarkdown source={preview} />
<br />
<a href="">Read more...</a>
Expand Down
2 changes: 1 addition & 1 deletion packages/service/src/components/video.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export let tags: Array<string> = [];
export let connected = false;
</script>

<Content type="Video" {...$$props}>
<Content {...$$props} type="Video">
<iframe id="player" width="600" height="340"
src={embed}
style="border:none"></iframe>
Expand Down
2 changes: 1 addition & 1 deletion packages/service/src/services/abstract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type ContentData = {
type: string;
name: string;
author: string;
lastUpdate: string;
lastUpdate?: string;
keywords: Array<string>;
description: string;
};
Expand Down
3 changes: 1 addition & 2 deletions packages/service/src/services/article-service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Memorize, longTermCache } from "../cache.js";
import {ComposedService, type ContentData, type ServiceInterface, type ServiceMetadata} from "./abstract.js";
import { ComposedService, type ContentData, type ServiceInterface, type ServiceMetadata } from "./abstract.js";

export const TYPE = "article";
export const RECIPE_TYPE = "recipe";
Expand All @@ -10,7 +10,6 @@ export class ArticleService extends ComposedService<{ preview: string }> {
}
}


export class RecipeService implements ServiceInterface<{ preview: string }> {
canHandle(metadata: ServiceMetadata): Promise<boolean> {
return Promise.resolve([RECIPE_TYPE, TYPE].includes(metadata.type));
Expand Down
135 changes: 135 additions & 0 deletions packages/service/src/services/guild-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { Memorize, longTermCache } from "../cache.js";
import type { ContentData, ServiceInterface, ServiceMetadata } from "./abstract.js";

export const TYPE = "guild" as const;

export class GuildService implements ServiceInterface<{ cover: string; members: number }> {
canHandle(metadata: ServiceMetadata): Promise<boolean> {
return Promise.resolve(metadata.type === TYPE);
}
async getInformation(metadata: ServiceMetadata): Promise<(ContentData & { cover: string; members: number }) | never> {
const guilds = await this.getGuilds();
let guild: GuildHostGuildNodeResponse | undefined = guilds.data.nodeBySlugId.guilds.edges.find(
(guild) => guild.node.slugId === metadata.identifier,
)?.node;

if (guild === undefined) {
guild = (await this.getOneGuild(metadata.identifier))?.data.nodeBySlugId;
}

if (guild === undefined) {
throw new Error("Invalid data service");
}

return {
name: guild.name,
description: guild.description,
type: TYPE,
author: "guild.host",
keywords: [],
members: guild.networkMembers.totalCount,
cover: guild.backgroundPhoto
? `https://ik.imagekit.io/guild/prod/tr:w-600,dpr-1/${guild.backgroundPhoto?.rowId}.${guild.backgroundPhoto?.contentType.toLowerCase()}`
: "",
};
}

@Memorize(longTermCache)
private getOneGuild(id: string): Promise<GuildHostOneResponse> {
return fetch("https://guild.host/graphql/1bab259132f26a669a0dbe5184260401be37f259bf888010711abab5438e8e51", {
headers: {
"X-Gqlvars": `{"id":"${id}"}`,
},
}).then((response) => response.json());
}

@Memorize(longTermCache)
private getGuilds(): Promise<GuildHostResponse> {
return fetch("https://guild.host/graphql/932d20dc08db4fb8d9f86e17908ba8ccb8b1de931ad51718689570c942c82c71", {
headers: {
"X-Gqlvars": '{"id":"svelte-society"}',
},
}).then((response) => response.json());
}

getAllServiceMetadata(): Promise<Array<ServiceMetadata>> {
return this.getGuilds().then((response) =>
response.data.nodeBySlugId.guilds.edges.map((guild) => ({
type: TYPE,
identifier: guild.node.slugId,
})),
);
}
}

type GuildHostResponse = {
data: {
nodeBySlugId: {
__typename: "Guild";
name: string;
slugId: string;
description: string;
networks: { edges: []; pageInfo: { endCursor: null; hasNextPage: boolean } };
id: string;
guilds: {
edges: Array<{
node: GuildHostGuildNodeResponse;
cursor: string;
}>;
pageInfo: { endCursor: string; hasNextPage: boolean };
};
__isNode: "Guild";
};
};
};

type GuildHostGuildNodeResponse = {
__typename: "Guild";
id: string;
slugId: string;
type: "NETWORK" | "GUILD";
myMembership: unknown;
minimumDonationAmount?: number;
donationCurrency?: "EUR";
rowId: string;
name: string;
description: string;
networkMembers: {
totalCount: number;
};
primaryPhoto: {
rowId: string;
contentType: "PNG" | "WEBP" | "JPEG";
id: string;
} | null;
backgroundPhoto: {
rowId: string;
contentType: "PNG" | "WEBP" | "JPEG";
id: string;
} | null;
totalNetworks?: {
edges: Array<unknown>;
};
totalGuilds?: {
edges: Array<{
cursor: string;
}>;
};
totalEvents?: {
edges: Array<{
cursor: string;
}>;
};
totalPresentations?: {
edges: Array<{
cursor: string;
}>;
};
__isNode?: "Guild";
};

type GuildHostOneResponse = {
data: {
nodeBySlugId: GuildHostGuildNodeResponse;
};
};
5 changes: 4 additions & 1 deletion sites/www/src/routes/(app)/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CollectorService } from 'sveltesociety.dev-service/src/collector.js';
import { GuildService } from 'sveltesociety.dev-service/src/services/guild-service';
import { ConnectedService } from 'sveltesociety.dev-service/src/services/society-stats-service.js';
import type { PageServerLoad } from './$types';

Expand All @@ -15,7 +16,9 @@ export const load: PageServerLoad = async () => {
{ type: 'video', identifier: '330781388' },
{ type: 'recipe', identifier: 'xxx' },
{ type: 'package', identifier: 'svelte' },
{ type: 'package', identifier: 'svelte-atoms' }
{ type: 'package', identifier: 'svelte-atoms' },
{ type: 'guild', identifier: 'london-javascript' },
...(await new GuildService().getAllServiceMetadata())
])
};
};
46 changes: 6 additions & 40 deletions sites/www/src/routes/(app)/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import Package from 'sveltesociety.dev-service/src/components/package.svelte';
import Recipe from 'sveltesociety.dev-service/src/components/recipe.svelte';
import Video from 'sveltesociety.dev-service/src/components/video.svelte';
import Guild from 'sveltesociety.dev-service/src/components/guild.svelte';
import type { PageData } from './$types';
export let data: PageData;
Expand All @@ -14,48 +15,13 @@ Home page!
<main>
{#each data.items as item}
{#if item.type === 'package'}
<Package
type="Library"
description={item.description}
name={item.name}
author={item.author}
lastUpdate={item.lastUpdate}
likes={item.likes}
tags={item.keywords}
cover={item.cover}
connected={item.connected}
views={item.views}
liked={item.liked}
saved={item.saved}
/>
<Package {...item} tags={item.keywords} />
{:else if item.type === 'video'}
<Video
description={item.description}
name={item.name}
author={item.author}
lastUpdate={item.lastUpdate}
likes={item.likes}
tags={item.keywords}
embed={item.embed}
connected={item.connected}
views={item.views}
liked={item.liked}
saved={item.saved}
/>
<Video {...item} tags={item.keywords} />
{:else if item.type === 'recipe'}
<Recipe
description={item.description}
name={item.name}
author={item.author}
lastUpdate={item.lastUpdate}
likes={item.likes}
tags={item.keywords}
preview={item.preview}
connected={item.connected}
views={item.views}
liked={item.liked}
saved={item.saved}
/>
<Recipe {...item} tags={item.keywords} />
{:else if item.type === 'guild'}
<Guild {...item} />
{/if}
{/each}
</main>
Expand Down

0 comments on commit 3b897e1

Please sign in to comment.