finished phew
This commit is contained in:
commit
9901fb06f0
18 changed files with 4336 additions and 0 deletions
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Output
|
||||||
|
.output
|
||||||
|
.vercel
|
||||||
|
/.svelte-kit
|
||||||
|
/build
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Env
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.test
|
||||||
|
|
||||||
|
# Vite
|
||||||
|
vite.config.js.timestamp-*
|
||||||
|
vite.config.ts.timestamp-*
|
||||||
1
.npmrc
Normal file
1
.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
engine-strict=true
|
||||||
38
README.md
Normal file
38
README.md
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# create-svelte
|
||||||
|
|
||||||
|
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
||||||
|
|
||||||
|
## Creating a project
|
||||||
|
|
||||||
|
If you're seeing this, you've probably already done this step. Congrats!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# create a new project in the current directory
|
||||||
|
npm create svelte@latest
|
||||||
|
|
||||||
|
# create a new project in my-app
|
||||||
|
npm create svelte@latest my-app
|
||||||
|
```
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
|
||||||
|
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# or start the server and open the app in a new browser tab
|
||||||
|
npm run dev -- --open
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
To create a production version of your app:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
You can preview the production build with `npm run preview`.
|
||||||
|
|
||||||
|
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
||||||
3802
package-lock.json
generated
Normal file
3802
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
28
package.json
Normal file
28
package.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "5th-site",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite dev",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@sveltejs/adapter-auto": "^3.0.0",
|
||||||
|
"@sveltejs/kit": "^2.0.0",
|
||||||
|
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"postcss": "^8.4.47",
|
||||||
|
"svelte": "^4.2.7",
|
||||||
|
"svelte-check": "^4.0.0",
|
||||||
|
"tailwindcss": "^3.4.14",
|
||||||
|
"typescript": "^5.0.0",
|
||||||
|
"vite": "^5.0.3"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@sveltejs/adapter-cloudflare": "^4.7.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
32
src/app.css
Normal file
32
src/app.css
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
* { @apply transition-all duration-500 ease-in-out; }
|
||||||
|
body { @apply bg-slate-950 text-gray-400 max-w-3xl mx-auto my-8 px-4; }
|
||||||
|
h1 { @apply text-3xl md:text-4xl font-semibold my-4; }
|
||||||
|
h2 { @apply text-2xl md:text-3xl font-bold my-4; }
|
||||||
|
h3 { @apply text-xl md:text-2xl font-bold my-4; }
|
||||||
|
h4 { @apply text-lg md:text-xl font-bold my-4; }
|
||||||
|
h5 { @apply text-base md:text-lg font-bold my-4; }
|
||||||
|
h6 { @apply text-sm md:text-base font-bold my-4; }
|
||||||
|
a { @apply text-sky-300 hover:text-sky-100 underline; }
|
||||||
|
article { @apply p-2 sm:p-4 text-slate-300; }
|
||||||
|
p { @apply my-4 text-sm sm:text-base; }
|
||||||
|
code { @apply bg-slate-800 p-0.5 rounded-md; }
|
||||||
|
pre { @apply bg-slate-800 p-4 rounded-md my-4 overflow-x-auto; }
|
||||||
|
blockquote { @apply bg-slate-800 text-gray-400 p-4; }
|
||||||
|
hr { @apply my-4 border-gray-700; }
|
||||||
|
ul { @apply list-disc ml-6; }
|
||||||
|
ol { @apply list-decimal ml-6; }
|
||||||
|
header { @apply flex flex-col justify-between items-center gap-4; }
|
||||||
|
nav { @apply flex gap-4; }
|
||||||
|
img { @apply object-cover object-center; }
|
||||||
|
form { @apply my-4 flex flex-col justify-center items-start; }
|
||||||
|
input { @apply m-1 py-1 px-2 w-full border bg-gray-700 text-gray-300; }
|
||||||
|
button { @apply m-1 py-1 px-2 w-full bg-gray-400 text-slate-900; }
|
||||||
|
footer { @apply my-4 text-center; }
|
||||||
|
table { @apply w-full my-4; }
|
||||||
|
thead { @apply bg-slate-800 text-gray-400; }
|
||||||
|
tbody { @apply bg-slate-900 text-slate-300; }
|
||||||
|
tr, th, td { @apply p-1 border border-gray-700; }
|
||||||
13
src/app.d.ts
vendored
Normal file
13
src/app.d.ts
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
// See https://kit.svelte.dev/docs/types#app
|
||||||
|
// for information about these interfaces
|
||||||
|
declare global {
|
||||||
|
namespace App {
|
||||||
|
// interface Error {}
|
||||||
|
// interface Locals {}
|
||||||
|
// interface PageData {}
|
||||||
|
// interface PageState {}
|
||||||
|
// interface Platform {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
12
src/app.html
Normal file
12
src/app.html
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
%sveltekit.head%
|
||||||
|
</head>
|
||||||
|
<body data-sveltekit-preload-data="hover">
|
||||||
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
196
src/lib/index.ts
Normal file
196
src/lib/index.ts
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
export function blog(api: string, base?: string) {
|
||||||
|
return fetch(`${api}/api/collections/blogs/records?page=1&perPage=1&fields=collectionId,id,title,desc,created,thumbnail&sort=-created`)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then((data: {
|
||||||
|
items: {
|
||||||
|
collectionId: string,
|
||||||
|
id: string,
|
||||||
|
title: string,
|
||||||
|
desc: string,
|
||||||
|
created: number,
|
||||||
|
thumbnail: string,
|
||||||
|
}[]
|
||||||
|
}) => {
|
||||||
|
const blog = data.items[0];
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: blog.title,
|
||||||
|
desc: blog.desc,
|
||||||
|
created: blog.created,
|
||||||
|
// thumbnail: `${api}/api/files/${blog.collectionId}/${blog.id}/${blog.thumbnail}?thumb=320x160`,
|
||||||
|
url: !base ? '' : `${base}/${blog.id}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function github(max: number, user: string) {
|
||||||
|
return fetch(`https://api.github.com/users/${user}/repos?per_page=${max}?type=owner&sort=created`)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then((data:
|
||||||
|
{
|
||||||
|
fork: boolean,
|
||||||
|
name: string,
|
||||||
|
description: string,
|
||||||
|
html_url: string,
|
||||||
|
stargazers_count: number,
|
||||||
|
language: string,
|
||||||
|
}[]
|
||||||
|
) => data.filter(repo => !repo.fork).slice(0, max).map(repo => ({
|
||||||
|
name: repo.name,
|
||||||
|
desc: repo.description,
|
||||||
|
url: repo.html_url,
|
||||||
|
stars: repo.stargazers_count,
|
||||||
|
lang: repo.language,
|
||||||
|
}))).catch((e) => [
|
||||||
|
{ name: 'Error', desc: e.message, url: '', stars: 0, lang: '' },
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function discord(id: string) {
|
||||||
|
return fetch(`https://api.lanyard.rest/v1/users/${id}`)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(({data}: {
|
||||||
|
data: {
|
||||||
|
discord_user: {
|
||||||
|
id: string,
|
||||||
|
username: string,
|
||||||
|
avatar: string,
|
||||||
|
},
|
||||||
|
discord_status: string,
|
||||||
|
spotify: {
|
||||||
|
album_art_url: string,
|
||||||
|
track_id: string,
|
||||||
|
song: string,
|
||||||
|
artist: string,
|
||||||
|
},
|
||||||
|
activities: {
|
||||||
|
type: number,
|
||||||
|
name: string,
|
||||||
|
created_at: number,
|
||||||
|
state: string,
|
||||||
|
details: string,
|
||||||
|
assets: {
|
||||||
|
large_image: string,
|
||||||
|
small_image: string,
|
||||||
|
},
|
||||||
|
application_id: string,
|
||||||
|
}[],
|
||||||
|
}
|
||||||
|
success: boolean,
|
||||||
|
}) => ({
|
||||||
|
// avatar: `https://cdn.discordapp.com/avatars/${data.discord_user.id}/${data.discord_user.avatar}.png?size=128`,
|
||||||
|
username: data.discord_user.username,
|
||||||
|
status: data.discord_status,
|
||||||
|
spotify: {
|
||||||
|
art: data?.spotify?.album_art_url,
|
||||||
|
link: `https://open.spotify.com/intl-id/track/${data?.spotify?.track_id}`,
|
||||||
|
song: data?.spotify?.song,
|
||||||
|
artist: data?.spotify?.artist,
|
||||||
|
},
|
||||||
|
activity: data?.activities.filter((a: {type:number}) =>a.type===0).map((activity:
|
||||||
|
{name: string, created_at: number, state: string, details: string, assets: {large_image: string, small_image: string}, application_id: string}
|
||||||
|
) => ({
|
||||||
|
name: activity.name,
|
||||||
|
started: activity.created_at,
|
||||||
|
state: activity.state,
|
||||||
|
details: activity.details,
|
||||||
|
images: {
|
||||||
|
large: !activity?.assets?.large_image ? '' : `https://cdn.discordapp.com/app-assets/${activity.application_id}/${activity?.assets?.large_image}.png?size=256`,
|
||||||
|
small: !activity?.assets?.small_image ? '' : `https://cdn.discordapp.com/app-assets/${activity.application_id}/${activity?.assets?.small_image}.png?size=256`,
|
||||||
|
},
|
||||||
|
})).sort((a: {started:number}, b: {started:number}) => b.started - a.started) || [],
|
||||||
|
})).catch(() => ({
|
||||||
|
username: 'Error',
|
||||||
|
status: 'Error',
|
||||||
|
spotify: {
|
||||||
|
art: '',
|
||||||
|
link: '',
|
||||||
|
song: '',
|
||||||
|
artist: '',
|
||||||
|
},
|
||||||
|
activity: [],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function daysUntilBirthday(date: number[]): number {
|
||||||
|
const today = new Date();
|
||||||
|
const birthday = new Date(today.getFullYear(), date[1] - 1, date[0]);
|
||||||
|
if (today > birthday) {
|
||||||
|
birthday.setFullYear(today.getFullYear() + 1);
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
return Math.ceil((birthday - today) / 86400000);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTimeIn(timezone: string): string {
|
||||||
|
const options = { timeZone: timezone, hour12: true, hour: 'numeric', minute: 'numeric' };
|
||||||
|
// @ts-ignore
|
||||||
|
const time = new Date().toLocaleString("en-US", options);
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function timeAgo(unixTimestamp: number): string {
|
||||||
|
const date = new Date(unixTimestamp);
|
||||||
|
// @ts-ignore
|
||||||
|
const seconds = Math.floor((new Date() - date) / 1000);
|
||||||
|
let interval = seconds / 31536000;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + " years ago";
|
||||||
|
}
|
||||||
|
interval = seconds / 2592000;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + " months ago";
|
||||||
|
}
|
||||||
|
interval = seconds / 86400;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + " days ago";
|
||||||
|
}
|
||||||
|
interval = seconds / 3600;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + " hours ago";
|
||||||
|
}
|
||||||
|
interval = seconds / 60;
|
||||||
|
if (interval > 1) {
|
||||||
|
return Math.floor(interval) + " minutes ago";
|
||||||
|
}
|
||||||
|
return Math.floor(seconds) + " seconds ago";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function randomStr(length: number): string {
|
||||||
|
let result = '';
|
||||||
|
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.toUpperCase();
|
||||||
|
const charactersLength = characters.length;
|
||||||
|
let counter = 0;
|
||||||
|
while (counter < length) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const months = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "satr14's site",
|
||||||
|
subtitle: "Howdy!",
|
||||||
|
name: "satr14",
|
||||||
|
legal: "Satria",
|
||||||
|
description: "I'm Satria (also known as satr14), Im a self-taught hobbyist web developer from Indonesia. I've been programming since 2021 and I love spending my free time working on personal projects and experimenting with new technologies.",
|
||||||
|
skills: ["HTML", "CSS", "JavaScript", "Tailwind", "Svelte", "SvelteKit", "NodeJS", "Express", "PocketBase", "Python", "Linux", "Nginx", "Docker", "Git", "Bash", "Proxmox", "Nix"],
|
||||||
|
birthday: [12,6],
|
||||||
|
timezone: "Asia/Jakarta",
|
||||||
|
links: {
|
||||||
|
"Blog website": "https://blog.satr14.my.id/",
|
||||||
|
"Terminal portfolio": "https://github.com/SX-9/term-port/",
|
||||||
|
"Project part-of.my.id": "https://part-of.my.id/",
|
||||||
|
"DVD logo bounce": "https://sx-9.github.io/dvd-bounce/",
|
||||||
|
"Chess from scratch": "https://sx-9.github.io/chess-from-scratch/",
|
||||||
|
},
|
||||||
|
discord: "882595027132493864",
|
||||||
|
github: "SX-9",
|
||||||
|
blog: {
|
||||||
|
api: "https://blog.satr14.my.id/pb",
|
||||||
|
base: "https://blog.satr14.my.id/post",
|
||||||
|
main: "https://blog.satr14.my.id/",
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/routes/+layout.server.ts
Normal file
14
src/routes/+layout.server.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import type { LayoutServerLoad } from './$types';
|
||||||
|
import info, { blog, discord, github } from '$lib';
|
||||||
|
|
||||||
|
export const ssr = true;
|
||||||
|
export const load = (async () => {
|
||||||
|
return {
|
||||||
|
...info,
|
||||||
|
fetched: {
|
||||||
|
discord: await discord(info.discord),
|
||||||
|
github: await github(7, info.github),
|
||||||
|
blog: await blog(info.blog.api, info.blog.base),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}) satisfies LayoutServerLoad;
|
||||||
13
src/routes/+layout.svelte
Normal file
13
src/routes/+layout.svelte
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { PageData } from './$types';
|
||||||
|
export let data: PageData;
|
||||||
|
import "../app.css";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{data.title}</title>
|
||||||
|
<meta name="description" content={data.description} />
|
||||||
|
<meta name="theme-color" content="#00e1ff" />
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<slot />
|
||||||
115
src/routes/+page.svelte
Normal file
115
src/routes/+page.svelte
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { daysUntilBirthday, discord, getTimeIn, months, randomStr, timeAgo } from "$lib";
|
||||||
|
import type { PageData } from "./$types";
|
||||||
|
export let data: PageData;
|
||||||
|
|
||||||
|
let days = daysUntilBirthday(data.birthday);
|
||||||
|
let time = getTimeIn(data.timezone);
|
||||||
|
let created = new Date(data.fetched.blog.created);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<div class="group border-2 border-slate-700 hover:border-slate-500 rounded-xl w-full h-32 overflow-hidden flex justify-center items-center shadow-lg">
|
||||||
|
<span class="text-center text-5xl font-mono my-4 cursor-default -rotate-6 leading-10 text-slate-500 group-hover:text-slate-700">
|
||||||
|
{randomStr(25)}<br>{randomStr(25)}
|
||||||
|
{randomStr(20-data.name.length/2)}<a href={'https://github.com/'+data.github+'/5th-site'} target="_blank" class="group-hover:px-2 no-underline text-slate-300 group-hover:text-slate-100">{data.name.toUpperCase()}</a>{randomStr(20-data.name.length/2)}
|
||||||
|
{randomStr(25)}<br>{randomStr(25)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<nav class="flex justify-center gap-4 text-lg max-w-full overflow-y-auto text-nowrap">
|
||||||
|
<a href={'https://github.com/'+data.github} target="_blank">github</a>
|
||||||
|
<a href={'https://discordapp.com/users/'+data.discord} target="_blank">discord</a>
|
||||||
|
<a href={data.blog.main} target="_blank">blog</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<article>
|
||||||
|
<h1>{data.subtitle}</h1>
|
||||||
|
<p>{data.description}</p>
|
||||||
|
<p class="text-sm italic">
|
||||||
|
<b>{days || 'Today'}</b> { days ? 'day' + (days === 1 ? '' : 's') + ' until my birthday.' : 'is my birthday!' }
|
||||||
|
It's <b>{time}</b> for me.
|
||||||
|
</p>
|
||||||
|
<p class="flex flex-wrap gap-2 text-sm">
|
||||||
|
{#each data.skills as skill}
|
||||||
|
<a href={'https://google.com/search?q='+skill} target="_blank" class="bg-slate-900 text-sky-100 hover:bg-slate-800 px-2 py-1 rounded-full no-underline">{skill}</a>
|
||||||
|
{/each}
|
||||||
|
</p>
|
||||||
|
<p class="flex flex-wrap gap-1">
|
||||||
|
{#each Object.entries(data.links) as link, i}
|
||||||
|
{#if i > 0}<span class="text-slate-300">~</span>{/if}
|
||||||
|
<a href={link[1]} target="_blank">{link[0]}</a>
|
||||||
|
{/each}
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
<section>
|
||||||
|
<h2 class="text-base italic m-0">Newest blog post</h2>
|
||||||
|
<h1 class="m-0 font-normal"><a class="no-underline" href={data.fetched.blog.url} target="_blank">{data.fetched.blog.title}</a></h1>
|
||||||
|
<p class="text-lg m-0">{months[created.getMonth()]} {created.getDate()}, {created.getFullYear()} - {data.fetched.blog.desc}</p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2 class="text-base italic m-0 mt-8">GitHub Repositories</h2>
|
||||||
|
<div class="flex flex-col gap-4 mt-2">
|
||||||
|
{#each data.fetched.github as repo, i}
|
||||||
|
<div class="flex justify-between items-center ">
|
||||||
|
<div>
|
||||||
|
<h3 class="m-0 font-normal"><a class="no-underline" href={repo.url} target="_blank">{repo.name}</a></h3>
|
||||||
|
<p class="m-0">{repo.desc}</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
{#if repo.lang}<span class="italic">{repo.lang}</span>{/if}<br>
|
||||||
|
{#if repo.stars}<span class="text-yellow-200"><b>{repo.stars}</b> star{repo.stars>1?'s':''}</span>{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2 class="text-base italic m-0 mt-8">Discord Status</h2>
|
||||||
|
<div class="flex flex-wrap my-4">
|
||||||
|
{#if data.fetched.discord.spotify.song}
|
||||||
|
<div class="m-4">
|
||||||
|
<div class="flex gap-2 items-center">
|
||||||
|
<img class="size-12 rounded-md" src={data.fetched.discord.spotify.art} alt="album art">
|
||||||
|
<div>
|
||||||
|
<h4 class="my-0"><a href={data.fetched.discord.spotify.link}>{data.fetched.discord.spotify.song}</a></h4>
|
||||||
|
<span class="italic">{data.fetched.discord.spotify.artist}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="italic text-sm">Listening to Spotify</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#each data.fetched.discord.activity as activity}
|
||||||
|
<div class="m-4">
|
||||||
|
<div class="flex gap-2 items-center">
|
||||||
|
<div class="relative">
|
||||||
|
{#if activity.images.large}
|
||||||
|
<img class="size-12 rounded-md" src={activity.images.large} alt="large">
|
||||||
|
{/if}
|
||||||
|
{#if activity.images.small}
|
||||||
|
<img class="size-6 rounded-full absolute -bottom-1 -right-1" src={activity.images.small} alt="small">
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<span class="italic">
|
||||||
|
Started {timeAgo(activity.started)}
|
||||||
|
{#if activity.state}
|
||||||
|
<br>{activity.state}
|
||||||
|
{/if}
|
||||||
|
{#if activity.details}
|
||||||
|
<br>{activity.details}
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span class="italic text-sm">Playing {activity.name}</span>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<h3 class="italic my-0 font-normal text-xl">@<span class="underline">{data.fetched.discord.username}</span> is <span class="data-[status=idle]:text-yellow-200 data-[status=dnd]:text-red-200 data-[status=online]:text-green-200" data-status={data.fetched.discord.status}>{data.fetched.discord.status}</span> in discord</h3>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<p class="text-center mt-8">
|
||||||
|
© {new Date().getFullYear()} {data.legal}. All rights reserved.
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
12
svelte.config.js
Normal file
12
svelte.config.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import adapter from '@sveltejs/adapter-cloudflare';
|
||||||
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
|
||||||
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
|
const config = {
|
||||||
|
preprocess: vitePreprocess(),
|
||||||
|
kit: {
|
||||||
|
adapter: adapter()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
8
tailwind.config.js
Normal file
8
tailwind.config.js
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||||
|
theme: {
|
||||||
|
extend: {}
|
||||||
|
},
|
||||||
|
plugins: []
|
||||||
|
};
|
||||||
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"extends": "./.svelte-kit/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "bundler"
|
||||||
|
}
|
||||||
|
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||||
|
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
|
||||||
|
//
|
||||||
|
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||||
|
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||||
|
}
|
||||||
6
vite.config.ts
Normal file
6
vite.config.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [sveltekit()]
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue