rainbow variant backend logic

This commit is contained in:
tglide
2024-01-15 19:22:53 +00:00
parent a474ef8a6e
commit 9430dcea1d
10 changed files with 432 additions and 55 deletions

View File

@@ -4,7 +4,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"build": "vite build", "build": "pnpm download-contributors && vite build",
"preview": "vite preview", "preview": "vite preview",
"test": "npm run test:integration && npm run test:unit", "test": "npm run test:integration && npm run test:unit",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
@@ -16,7 +16,8 @@
"test:unit": "vitest", "test:unit": "vitest",
"icons:build": "node ./src/icons/build.js", "icons:build": "node ./src/icons/build.js",
"icons:optimize": "node ./src/icons/optimize.js", "icons:optimize": "node ./src/icons/optimize.js",
"icons:generate": "node ./src/icons/optimize.js && node ./src/icons/build.js" "icons:generate": "node ./src/icons/optimize.js && node ./src/icons/build.js",
"download-contributors": "node ./src/scripts/download-contributor-data.js"
}, },
"devDependencies": { "devDependencies": {
"@melt-ui/pp": "^0.1.4", "@melt-ui/pp": "^0.1.4",

View File

@@ -0,0 +1,45 @@
import fs from 'fs';
const apiUrl = 'https://api.github.com/repos/appwrite/appwrite/contributors';
const perPage = 100;
const outputFile = `./src/lib/contributors.ts`;
async function fetchContributors() {
let page = 1;
let contributorsData = [];
let hasMoreData = true;
while (hasMoreData) {
console.log(page);
const url = `${apiUrl}?page=${page}&per_page=${perPage}`;
const response = await fetch(url);
if (!response.ok) {
console.error(`Failed to fetch data from ${url}`);
break;
}
const data = await response.json();
if (data.length === 0) {
hasMoreData = false;
} else {
contributorsData = contributorsData.concat(data.map((c) => c.login));
page++;
}
}
if (contributorsData.length > 0) {
// Write the concatenated data to a JSON file
fs.writeFileSync(
outputFile,
`export const contributors = ${JSON.stringify(contributorsData, null, 2)}`
);
console.log(`Contributor data saved to ${outputFile}`);
} else {
console.log('No contributor data found.');
}
}
fetchContributors();

324
src/lib/contributors.ts Normal file
View File

@@ -0,0 +1,324 @@
export const contributors = [
"eldadfux",
"TorstenDittmann",
"christyjacob4",
"lohanidamodar",
"abnegate",
"Meldiron",
"shimonewman",
"PineappleIOnic",
"kodumbeats",
"stnguyen90",
"fogelito",
"everly-gif",
"vermakhushboo",
"2002Bishwajeet",
"gewenyu99",
"fanatic75",
"VocalFan",
"brandonroberts",
"wess",
"adityaoberai",
"armino-dev",
"gepd",
"elad2412",
"singhbhaskar",
"rdmchr",
"BobcatProgrammer",
"tacoelho",
"tusharxoxoxo",
"bogdaaamn",
"hack3r-0m",
"Aragur",
"fernandoamz",
"MrKrishnaAgarwal",
"dependabot[bot]",
"Ln11211",
"dependabot-preview[bot]",
"loks0n",
"NeonSpork",
"TricksterNerd",
"Haimantika",
"tanay1337",
"safwanyp",
"the-bose",
"tomer",
"Vinatk",
"prasanjit15",
"estim",
"Priyanka788",
"YMsyaraf",
"Glide7",
"krishvsoni",
"daniloff200",
"TafadzwaD",
"Akshay-Rana-Gujjar",
"sagarvd01",
"stvmachine",
"W4nn4Die",
"snyk-bot",
"itaymelamed",
"toir427",
"spielers",
"Sayanta66",
"NidhxGupta",
"naman360",
"MasterKN48",
"Ganzabahl",
"iamdineshkumar",
"alenros",
"Malte2036",
"iamrajiv",
"rjn01",
"cho0o0",
"lex111",
"SuuSoJeat",
"eliely",
"yatharth1706",
"arsheelsheikh",
"jaivix",
"mostafahussein",
"MissaDavid",
"AnatoleLucet",
"dazzlerkumar",
"HelloSeaNation",
"stijnvdkolk",
"mbos2",
"aerabi",
"Olyno",
"SoftCreatR",
"varghesejose2020",
"xtmprsqzntwlfb",
"ayan-b",
"geisterfurz007",
"irajtaghlidi",
"megatank58",
"munyoudoum",
"rsneh",
"sakshamtaneja21",
"syshcndr",
"vaibhavagarwal220",
"vrabe",
"willtryagain",
"DH-555",
"Kokoden",
"m1ga",
"OscarRG",
"RizkyRajitha",
"Rutam21",
"Shrey-Nahar",
"ahmedkrmn",
"codercatdev",
"alexweininger",
"didair",
"antoine29",
"AshishMhrzn10",
"balazsbotond",
"Doges",
"DenverCoder1",
"gaby",
"JulianWebb",
"ronfybish",
"rskbansal",
"tanishqchamola",
"Suven-p",
"TheLearneer",
"PrerakMathur20",
"sesam",
"24sharkS",
"pranjalg13",
"fenix-hub",
"minna-xD",
"KaranSinghBisht",
"ravijyoti3",
"karniv00l",
"renato04",
"Taminoful",
"zswati",
"utkarsh-raj",
"valerianpereira",
"chuiizeet",
"fanlan1210",
"izqalan",
"kristofkalocsai",
"tosbaha",
"teeradon43",
"TGlide",
"sakthi-goutham",
"vimode",
"pomarec",
"kiy4h",
"jakubhi",
"honeykpatel",
"Dhruvacube",
"Hrdtr",
"ErfanBahramali",
"emattiza",
"anoopmsivadas",
"byawitz",
"achromik",
"codingsamurai-10",
"Carike",
"arsangamal",
"srivastavaayu",
"aayushbisen",
"chandrikadeb7",
"Exouxas",
"chuongtang",
"Conor0Callaghan",
"Dksie09",
"Parikshit-Hooda",
"Nikhil-1503",
"michizhou",
"MATsxm",
"kostapappas",
"ks129",
"jonsandg",
"brocococonut",
"eltociear",
"friederbluemle",
"iifawzi",
"EricBrianAnil",
"deshankoswatte",
"KaminskiDaniell",
"saintmalik",
"sudvincic",
"sakkshm",
"sm-raiyyan",
"RReiso",
"ssong",
"santoshyadavdev",
"sarthakroy2002",
"sergivb01",
"Spooky9",
"fanksin",
"Tinywan",
"silvia-odwyer",
"sombit-g",
"bharatr21",
"mishmanners",
"MohanSha",
"MukulKolpe",
"nataliarossini",
"torn4dom4n",
"Niladri24dutta",
"Nitesh-thapliyal",
"1qk1",
"parshnt",
"fatrixienicolieopetina",
"pedrowoy",
"Pranav2612000",
"Atsurak",
"Ratna04priya",
"rinkuhasija",
"rishav142k",
"rubensdemelo",
"RukmalFernando",
"hdkhoasgt",
"jakaya123",
"kaczmarekdaniel",
"lucianosz7",
"mananchawla2005",
"motasimmakki",
"navneetsn18",
"nocategory",
"oovk",
"oriolhub",
"peter279k",
"SevenIndirecto",
"siw3kosky",
"74616e696d",
"und1n3",
"vj-codes",
"waridrox",
"wenzdey",
"Sooraj-s-98",
"srijit2002",
"AbsolemJackdaw",
"sumitkharche",
"Sushrut1101",
"takmar",
"pcgeek86",
"wslaghekke",
"WonderfulWan8",
"Yash-Garg",
"YohskDista",
"Zerplin",
"alvesgabriel",
"Chaaarles",
"divshacker",
"faisalill",
"haktober",
"harshita214",
"Biki-das",
"BoynChan",
"ozdemirburak",
"Girxffe",
"cpuppireddy",
"mazedlx",
"DEBSUBHRO",
"dyyim741",
"danibjor",
"drandell",
"davidmartos96",
"DekelKan",
"scopsy",
"dimshik100",
"fishmandev",
"EstherAF",
"ffranchina",
"0xflotus",
"1995YogeshSharma",
"A1zippo1",
"aadarshadhakalg",
"btme0011",
"akljohny",
"akshitsarin",
"Defkon1",
"Swinkid",
"AmreshSinha",
"anirudh-kac",
"SantosAntero",
"acalatrava",
"asperduti",
"asmitbm",
"baishakhi9931",
"flyfishingbarbara",
"iMacHumphries",
"jdorfman",
"justinnoel",
"kalpeshtated",
"khyativalera",
"xkrishguptaa",
"LiTO773",
"LorenzHenk",
"keul",
"lucasctd",
"banaboi",
"manaswinidas",
"mantasdb",
"TheMardy",
"matigumma",
"MatteoGheza",
"panz3r",
"mendelgordon",
"Miguelii",
"g3offrey",
"gireeshp",
"GisliNielsen",
"marinoffDev",
"Gustl22",
"gy741",
"haardikdharma10",
"helios1101",
"hillarysousa",
"NeelPatel001",
"INFERN04",
"ishanvyas22",
"IshankaDSenevirathne",
"JacquesFourieAUZ",
"jansenarruda",
"JaswanthRemiel",
"Virtual1",
"jessescn"
]

View File

@@ -1,30 +1,24 @@
<script lang="ts" context="module">
export type ContributionsMatrix = number[][];
export type TicketVariant = 'default' | 'pink' | 'rainbow';
export type TicketProps = {
name?: string;
user?: string;
id: number;
tribe?: string | null;
contributions?: ContributionsMatrix;
variant?: TicketVariant;
};
</script>
<script lang="ts"> <script lang="ts">
import { toScale } from '$lib/utils/toScale'; import { toScale } from '$lib/utils/toScale';
import { quadInOut } from 'svelte/easing'; import { quadInOut } from 'svelte/easing';
import { fade, type TransitionConfig } from 'svelte/transition'; import { fade, type TransitionConfig } from 'svelte/transition';
import Logo from '../(assets)/logo.svg';
import BG from '../(assets)/ticket-bg.svg';
import BgPink from '../(assets)/ticket-bg-pink.svg';
import ShineSvg from '../(assets)/shine.svg';
import ShinePink from '../(assets)/shine-pink.svg';
import Glow from '../(assets)/glow.svg'; import Glow from '../(assets)/glow.svg';
import Logo from '../(assets)/logo.svg';
import ShinePink from '../(assets)/shine-pink.svg';
import ShineSvg from '../(assets)/shine.svg';
import BgPink from '../(assets)/ticket-bg-pink.svg';
import BG from '../(assets)/ticket-bg.svg';
import type { TicketData } from '../ticket/constants';
type $$Props = TicketProps; type $$Props = Omit<TicketData, '$id'>;
$: ({ name, user, id, tribe, contributions, variant = 'default' } = $$props as $$Props); $: ({
name,
gh_user,
id,
tribe = null,
contributions,
variant = 'default'
} = $$props as $$Props);
$: bg = { $: bg = {
default: BG, default: BG,
@@ -59,8 +53,8 @@
<div class="ticket" data-variant={variant}> <div class="ticket" data-variant={variant}>
<img src={bg} alt="" class="bg" /> <img src={bg} alt="" class="bg" />
<p class="aw-title aw-u-color-text-primary">{name?.trim() || '-'}</p> <p class="aw-title aw-u-color-text-primary">{name?.trim() || '-'}</p>
{#if user} {#if gh_user}
<p class="aw-label">@{user}</p> <p class="aw-label">@{gh_user}</p>
{/if} {/if}
<div class="bottom-left"> <div class="bottom-left">
<img src={Logo} alt="init_" /> <img src={Logo} alt="init_" />

View File

@@ -1,11 +1,12 @@
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID } from '$env/static/public';
import { appwriteInit } from '$lib/appwrite/init'; import { appwriteInit } from '$lib/appwrite/init';
import { ID, Query } from 'appwrite';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { get, writable } from 'svelte/store'; import { get, writable } from 'svelte/store';
import type { ContributionsMatrix } from './(components)/Ticket.svelte';
import { PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID } from '$env/static/public'; import type { ContributionsMatrix, TicketData, TicketVariant } from './ticket/constants';
import { ID, Query } from 'appwrite'; import { contributors } from '$lib/contributors';
import type { Ticket } from './ticket/constants';
export function createCountdown(date: Date) { export function createCountdown(date: Date) {
const today = new Date(); const today = new Date();
@@ -233,7 +234,7 @@ export async function getTicketDocByUser({ login, name }: GithubUser) {
); );
if (total) { if (total) {
return documents[0] as unknown as Omit<Ticket, 'contributions'>; return documents[0] as unknown as Omit<TicketData, 'contributions' | 'variant'>;
} else { } else {
const allDocs = await appwriteInit.database.listDocuments( const allDocs = await appwriteInit.database.listDocuments(
PUBLIC_APPWRITE_DB_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID,
@@ -248,7 +249,7 @@ export async function getTicketDocByUser({ login, name }: GithubUser) {
id: allDocs.total + 1, id: allDocs.total + 1,
name name
} }
)) as unknown as Omit<Ticket, 'contributions'>; )) as unknown as Omit<TicketData, 'contributions' | 'variant'>;
} }
} }
@@ -257,7 +258,7 @@ export async function getTicketDocById(id: string) {
PUBLIC_APPWRITE_DB_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID,
PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_COL_INIT_ID,
id id
)) as unknown as Omit<Ticket, 'contributions'>; )) as unknown as Omit<TicketData, 'contributions' | 'variant'>;
} }
export async function getTicketContributions(id: string, f = fetch): Promise<ContributionsMatrix> { export async function getTicketContributions(id: string, f = fetch): Promise<ContributionsMatrix> {
@@ -267,22 +268,36 @@ export async function getTicketContributions(id: string, f = fetch): Promise<Con
return contributions ?? []; return contributions ?? [];
} }
function getTicketVariant(doc: Omit<TicketData, 'contributions' | 'variant'>): TicketVariant {
const { gh_user } = doc;
if (gh_user && contributors.includes(gh_user)) {
return 'rainbow';
}
return 'default';
// TODO: include pink variant
}
export async function getTicketByUser(user: GithubUser) { export async function getTicketByUser(user: GithubUser) {
const doc = await getTicketDocByUser(user); const doc = await getTicketDocByUser(user);
const contributions = await getTicketContributions(doc.$id); const contributions = await getTicketContributions(doc.$id);
const variant = getTicketVariant(doc);
return { return {
...doc, ...doc,
contributions contributions,
} as Ticket; variant
} as TicketData;
} }
export async function getTicketById(id: string, f = fetch) { export async function getTicketById(id: string, f = fetch) {
const doc = await getTicketDocById(id); const doc = await getTicketDocById(id);
const contributions = await getTicketContributions(doc.$id, f); const contributions = await getTicketContributions(doc.$id, f);
const variant = getTicketVariant(doc);
return { return {
...doc, ...doc,
contributions contributions,
} as Ticket; variant
} as TicketData;
} }

View File

@@ -70,13 +70,13 @@
<div class="ticket-2"> <div class="ticket-2">
<Ticket <Ticket
name="Eldad" name="Eldad"
user="eldadfux" gh_user="eldadfux"
id={1} id={1}
contributions={getMockContributions()} contributions={getMockContributions()}
/> />
</div> </div>
<div class="ticket-3"> <div class="ticket-3">
<Ticket name="Sara" user="sara_k" id={10} /> <Ticket name="Sara" gh_user="sara_k" id={10} />
</div> </div>
</TicketPreview> </TicketPreview>
</div> </div>

View File

@@ -1,7 +1,7 @@
import { PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID } from '$env/static/public'; import { PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID } from '$env/static/public';
import { appwriteInit } from '$lib/appwrite/init.js'; import { appwriteInit } from '$lib/appwrite/init.js';
import type { ContributionsMatrix } from '$routes/init/(components)/Ticket.svelte'; import type { ContributionsMatrix } from '$routes/init/(components)/Ticket.svelte';
import type { Ticket } from '../../constants.js'; import type { TicketData } from '../../constants.js';
import { parse } from 'node-html-parser'; import { parse } from 'node-html-parser';
const emptyResponse = new Response(JSON.stringify({ data: null }), { const emptyResponse = new Response(JSON.stringify({ data: null }), {
@@ -16,7 +16,7 @@ export async function GET({ params }) {
PUBLIC_APPWRITE_DB_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID,
PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_COL_INIT_ID,
params.id params.id
)) as unknown as Ticket; )) as unknown as TicketData;
const res = await fetch(`https://github.com/${gh_user}`); const res = await fetch(`https://github.com/${gh_user}`);
const html = await res.text(); const html = await res.text();

View File

@@ -1,9 +1,9 @@
import { PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID } from '$env/static/public'; import { PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID } from '$env/static/public';
import { appwriteInit } from '$lib/appwrite/init.js'; import { appwriteInit } from '$lib/appwrite/init.js';
import type { Ticket } from '../../constants.js'; import type { TicketData } from '../../constants.js';
import sharp from 'sharp'; import sharp from 'sharp';
const getSvg = (ticket: Ticket) => ` const getSvg = (ticket: TicketData) => `
<svg width="438" height="249" viewBox="0 0 438 249" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="438" height="249" viewBox="0 0 438 249" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_b_327_1972)"> <g filter="url(#filter0_b_327_1972)">
<g clip-path="url(#clip0_327_1972)"> <g clip-path="url(#clip0_327_1972)">
@@ -824,7 +824,7 @@ export async function GET({ params }) {
PUBLIC_APPWRITE_DB_INIT_ID, PUBLIC_APPWRITE_DB_INIT_ID,
PUBLIC_APPWRITE_COL_INIT_ID, PUBLIC_APPWRITE_COL_INIT_ID,
params.id params.id
)) as unknown as Ticket; )) as unknown as TicketData;
const svg = getSvg(ticket); const svg = getSvg(ticket);
const svgBuffer = Buffer.from(svg); const svgBuffer = Buffer.from(svg);

View File

@@ -1,17 +1,21 @@
import { invalidate } from '$app/navigation'; import { invalidate } from '$app/navigation';
import type { Models } from 'appwrite'; import type { Models } from 'appwrite';
import type { ContributionsMatrix } from '../(components)/Ticket.svelte';
export const TICKET_DEP = 'ticket'; export const TICKET_DEP = 'ticket';
export const invalidateTicket = () => { export const invalidateTicket = () => {
invalidate(TICKET_DEP); invalidate(TICKET_DEP);
}; };
export type Ticket = Pick<Models.Document, '$id'> & { export type ContributionsMatrix = number[][];
export type TicketVariant = 'default' | 'pink' | 'rainbow';
export type TicketData = Pick<Models.Document, '$id'> & {
name: string; name: string;
tribe: string; tribe?: string;
gh_user: string; gh_user?: string;
id: number; id: number;
show_contributions: boolean; show_contributions?: boolean;
contributions?: ContributionsMatrix; contributions?: ContributionsMatrix;
variant?: TicketVariant;
}; };

View File

@@ -117,13 +117,7 @@
<TicketPreview> <TicketPreview>
<div class="ticket-holder"> <div class="ticket-holder">
<Ticket <Ticket {...data.ticket} />
{name}
user={data.ticket?.gh_user}
id={data.ticket?.id ?? 0}
{tribe}
contributions={showGitHub ? data.ticket.contributions : undefined}
/>
</div> </div>
</TicketPreview> </TicketPreview>
</div> </div>