Compare commits

..

2 Commits

Author SHA1 Message Date
Reinaldy Rafli b1dc2b618d
feat(client): initial migration to astro 2024-02-11 21:16:39 +07:00
Reinaldy Rafli 952e07a5ae
chore: add funding 2024-02-11 19:59:53 +07:00
47 changed files with 11651 additions and 5665 deletions

2
.github/FUNDING.yml vendored
View File

@ -1 +1,3 @@
github: aldy505
ko_fi: aldy505
liberapay: aldy505

View File

@ -38,7 +38,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Installling dependencies
run: go mod download
@ -57,15 +57,16 @@ jobs:
REDIS_URL: redis://@redis:6379
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: go
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
- name: Create Sentry release
uses: getsentry/action-release@v1
continue-on-error: true
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
@ -75,7 +76,7 @@ jobs:
set_commits: skip
version: ${{ github.sha }}
- uses: codecov/codecov-action@v2
- uses: codecov/codecov-action@v4
with:
flags: api
@ -90,7 +91,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Installling dependencies
run: npm install
@ -106,15 +107,16 @@ jobs:
VITE_API_ENDPOINT: https://jokesbapak2.reinaldyrafli.com/api/v1
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
- name: Create Sentry release
uses: getsentry/action-release@v1
continue-on-error: true
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}

View File

@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install dependencies
run: npm install
@ -35,12 +35,12 @@ jobs:
VITE_API_ENDPOINT: https://jokesbapak2.reinaldyrafli.com/api/v1
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
api-build:
name: API
@ -75,7 +75,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Installling dependencies
run: go mod download
@ -94,13 +94,13 @@ jobs:
REDIS_URL: redis://@redis:6379
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: go
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
- uses: codecov/codecov-action@v2
- uses: codecov/codecov-action@v4
with:
flags: api

View File

@ -68,7 +68,7 @@ Jokes Bapak2 API is licensed under [GNU GENERAL PUBLIC LICENSE v3 license](./LIC
```
Jokes Bapak2 API is a free-to-use image API of Indonesian dad jokes.
Copyright (C) 2021-present Jokes Bapak2 Contributors
Copyright (C) 2021-present Reinaldy Rafli <aldy505@proton.me>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,4 +1,4 @@
VITE_NODE_ENV=development
VITE_SERVER_API_ENDPOINT=
VITE_BROWSER_API_ENDPOINT=
VITE_SENTRY_DSN=
NODE_ENV=development
SERVER_API_ENDPOINT=
BROWSER_API_ENDPOINT=
SENTRY_DSN=

View File

@ -1,19 +1,24 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier', 'plugin:svelte/prettier'],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier', "plugin:astro/recommended",],
plugins: ['@typescript-eslint'],
ignorePatterns: ['*.cjs'],
settings: {
'svelte3/typescript': () => require('typescript')
},
overrides: [
{
files: ["*.svelte"],
parser: "svelte-eslint-parser",
// Parse the `<script>` in `.svelte` as TypeScript by adding the following configuration.
// Define the configuration for `.astro` file.
files: ["*.astro"],
// Allows Astro components to be parsed.
parser: "astro-eslint-parser",
// Parse the script in `.astro` as TypeScript by adding the following configuration.
// It's the setting you need when using TypeScript.
parserOptions: {
parser: "@typescript-eslint/parser",
extraFileExtensions: [".astro"],
},
rules: {
// override/add rules settings here, such as:
// "astro/no-set-html-directive": "error"
},
},
],

View File

@ -1 +1 @@
v18.17
v20

View File

@ -6,8 +6,5 @@
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 120,
"plugins": [
"prettier-plugin-svelte"
]
"printWidth": 120
}

15
client/astro.config.mjs Normal file
View File

@ -0,0 +1,15 @@
import { defineConfig } from 'astro/config';
import UnoCSS from '@unocss/astro'
// https://astro.build/config
export default defineConfig({
i18n: {
defaultLocale: "en",
locales: ["en", "id"]
},
integrations: [
UnoCSS({
injectReset: true
}),
],
});

8382
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,45 +5,38 @@
"contributors": [
{
"name": "Reinaldy Rafli",
"email": "aldy505@tutanota.com",
"email": "aldy505@proton.me",
"url": "https://github.com/aldy505"
}
],
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "eslint --fix --ext .svelte,.js,.ts --ignore-path .gitignore .",
"format": "prettier --write --ignore-path .gitignore --plugin-search-dir=. \"./**/*.(ts|json|js|svelte)\""
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro",
"lint": "eslint --fix --ext .astro,.js,.ts --ignore-path .gitignore .",
"format": "prettier --write --ignore-path .gitignore --plugin-search-dir=. \"./**/*.(ts|json|js|astro)\""
},
"devDependencies": {
"@sveltejs/adapter-node": "1.3.1",
"@sveltejs/kit": "^1.22.5",
"@typescript-eslint/eslint-plugin": "6.3.0",
"@typescript-eslint/parser": "6.3.0",
"cssnano": "6.0.1",
"eslint": "8.47.0",
"eslint-config-prettier": "9.0.0",
"eslint-plugin-svelte": "2.32.4",
"eslint-plugin-astro": "^0.31.4",
"prettier": "3.0.1",
"prettier-plugin-svelte": "3.0.3",
"svelte": "4.2.0",
"svelte-check": "3.5.0",
"svelte-preprocess": "5.0.4",
"svelte-windicss-preprocess": "4.2.8",
"tslib": "2.6.1",
"typescript": "5.1.6",
"vite": "^4.4.9"
"typescript": "5.3.3"
},
"dependencies": {
"@astrojs/check": "^0.5.2",
"@fontsource/fira-mono": "5.0.8",
"@fontsource/rubik": "5.0.8",
"@sentry/browser": "7.63.0",
"dotenv": "16.3.1",
"ohmyfetch": "0.4.21",
"svelte-i18n": "3.7.0"
"@sentry/astro": "^7.100.1",
"@unocss/astro": "^0.58.5",
"@unocss/reset": "^0.58.5",
"astro": "^4.3.5",
"unocss": "^0.58.5"
}
}

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

Before

Width:  |  Height:  |  Size: 306 KiB

After

Width:  |  Height:  |  Size: 302 KiB

View File

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -1,13 +1,19 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { _ } from 'svelte-i18n';
---
import { getAbsoluteLocaleUrl } from "astro:i18n";
import * as indonesianTranslation from "../languages/id.json";
import * as englishTranslation from "../languages/en.json";
let open = false;
let duration = 0.4;
let burgerColor = 'rgb(18.4, 18.4, 18.4)';
let menuColor = 'rgb(180, 180, 180)';
</script>
---
<script>
export function goto(path: string) {
getAbsoluteLocaleUrl()
}
</script>
<nav class="flex flex-row py-6 font-body items-center">
<div class="hover:cursor-pointer flex-5 font-bold text-2xl" on:click={() => goto('/')}>Jokesbapak2</div>
<div class="navigation-item" on:click={() => goto('/why')}>{$_('navigation.why')}</div>
@ -48,14 +54,14 @@
</div>
</nav>
{#if open}
{open &&
<menu
class="top-of-the-world dark:bg-gray-900 dark:text-white bg-lavender-200 bg-gradient-to-br to-lavender-400 dark:to-lavender-900 text-black w-full h-full overscroll-none"
>
<div class="container -pr-10">
<div class="flex flex-col items-center content-center text-center pt-20">
<div
on:click={() => {
onclick={() => {
open = false;
return goto('/');
}}
@ -93,7 +99,7 @@
</div>
</div>
</menu>
{/if}
}
<style>
.navigation-item {

View File

@ -1,6 +1,6 @@
<script lang="ts">
export let emoji = '';
</script>
---
let emoji = '';
---
<div
class="bg-chetwode-200 dark:bg-chetwode-800 font-body px-4 md:px-8 py-6 md:my-8 rounded-lg text-black dark:text-white shadow-xl bg-gradient-to-br from-transparent to-chetwode-300 dark:to-chetwode-900"

1
client/src/env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="astro/client" />

View File

@ -1 +0,0 @@
/// <reference types="@sveltejs/kit" />

View File

@ -1,7 +0,0 @@
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = ({ event, resolve }) => {
return resolve(event, {
transformPageChunk: ({ html }) => html.replace('%lang%', 'en'),
});
};

View File

@ -0,0 +1,100 @@
---
import '@fontsource/fira-mono';
import '@fontsource/rubik';
import Navbar from '../components/Navbar.astro';
const { lang } = Astro.props;
const currentPath = Astro.url.path.replace("/en/", "/").replace("/id/", "/");
const translations = {
id: {
footer: {
"made": "Diciptakan dengan",
"indonesia": "di Indonesia",
"available": "Proyek ini tersedia di",
"github": "Github",
"language": "Bahasa:",
"english": "Inggris",
"indonesian": "Indonesia"
}
},
en: {
footer: {
"made": "Made with",
"indonesia": "in Indonesia",
"available": "This project is available on",
"github": "Github",
"language": "Languages:",
"english": "English",
"indonesian": "Indonesian"
}
},
};
---
<!DOCTYPE html>
<html lang={lang}>
<head>
<meta charset="utf-8"/>
<link href="/favicon.png" rel="icon"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="jokesbapak2, jokes, bapak2, indonesian, dad, jokes, api, rest" name="keywords"/>
<meta content="Reinaldy Rafli" name="author"/>
<meta content="#f4a9f5" name="theme-color"/>
<meta content="https://jokesbapak2.reinaldyrafli.com/" name="publisher"/>
<meta content="/social.jpg" property="og:image"/>
<meta content="Jokesbapak2 - Largest collection of Indonesian dad jokes" property="og:image:alt"/>
<meta content="/social.jpg" property="og:image:secure_url"/>
<meta content="1280" property="og:image:width"/>
<meta content="640" property="og:image:height"/>
<meta content="en_US" property="og:locale"/>
<meta content="website" property="og:type"/>
<meta content="summary_large_image" name="twitter:card"/>
<meta content="/social.jpg" name="twitter:image:src"/>
<meta content="/social.jpg" name="twitter:image"/>
<meta content="Reinaldy Rafli" name="twitter:creator"/>
<link href="/favicon.png" rel="icon" type="image/png">
<link href="/favicon.svg" rel="icon" type="image/svg">
%sveltekit.head%
</head>
<body>
<div
class="bg-gradient-to-br from-transparent to-lavender-300 dark:(bg-gray-900 to-lavender-900 text-white) min-h-screen h-full w-full"
>
<div class="container mx-auto xl:px-40 lg:px-28 md:px-20 sm:px-12 px-8 w-full">
<header>
<Navbar />
</header>
<main class="font-body">
<slot />
</main>
<footer class="font-body py-8 w-full md:w-1/2 lg:w-2/5">
<div class="flex flex-col md:flex-row flex-wrap">
<div class="flex-initial pr-3">
<p class="text-sm opacity-50 hover:opacity-90 transition duration-300 ease-in-out inline-block">
{translations[lang].footer.made} <span class="text-red-500">&#10084;</span>
{translations[lang].footer.indonesia}.
</p>
</div>
<div class="flex-initial pr-3">
<p class="text-sm opacity-50 hover:opacity-90 transition duration-300 ease-in-out inline-block">
{translations[lang].footer.available}
<a class="hover:underline" href="https://www.github.com/aldy505/jokes-bapak2">{translations[lang].footer.github}</a>.
</p>
</div>
<div class="flex-initial pr-3">
<p class="text-sm opacity-50 hover:opacity-90 transition duration-300 ease-in-out inline-block">
{translations[lang].footer.language}
<a class="hover:underline" href={`/en/${currentPath}`} target="_top">{translations[lang].footer.english}</a>
|
<a class="hover:underline" href={`/id/${currentPath}`} target="_top">{translations[lang].footer.indonesian}</a>.
</p>
</div>
</div>
</footer>
</div>
</div>
</body>
</html>

View File

@ -1,6 +0,0 @@
export default {
SERVER_API_ENDPOINT: import.meta.env.VITE_SERVER_API_ENDPOINT || 'http://localhost:5000',
BROWSER_API_ENDPOINT: import.meta.env.VITE_BROWSER_API_ENDPOINT || 'https://jokesbapak2.reinaldyrafli.com',
SENTRY_DSN: import.meta.env.VITE_SENTRY_DSN || '',
NODE_ENV: import.meta.env.VITE_NODE_ENV || 'development',
};

View File

@ -1,15 +0,0 @@
import { addMessages, getLocaleFromNavigator, getLocaleFromQueryString, init } from 'svelte-i18n';
import en from '../languages/en.json';
import id from '../languages/id.json';
addMessages('en', en);
addMessages('en-US', en);
addMessages('en-GB', en);
addMessages('id', id);
addMessages('id-ID', id);
init({
fallbackLocale: 'en',
initialLocale: getLocaleFromQueryString('lang') || getLocaleFromNavigator(),
});

View File

@ -1,10 +0,0 @@
import * as Sentry from '@sentry/browser';
import env from './env';
Sentry.init({
dsn: String(env.SENTRY_DSN) || '',
enabled: String(env.NODE_ENV) === 'production',
tracesSampleRate: 0.5,
});
export default Sentry;

View File

@ -0,0 +1,77 @@
---
// This page is meant to explain available API endpoints.
import Codeblock from '../../components/Codeblock.astro';
import Notice from '../../components/Notice.astro';
import Layout from '../../layout/Layout.astro';
const totalJokes = async (): Promise<string> => {
const response = await fetch(`${import.meta.env.API_ENDPOINT}/total`);
const responseBody = await response.json();
return responseBody.message;
};
let total = await totalJokes();
---
<!-- <svelte:head>
<title>{$_('navigation.api')} - {$_('meta.title')}</title>
<meta content={$_('navigation.api') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.api') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.api') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/api" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head> -->
<Layout>
<section>
<Notice emoji="💡">
We limit the request to be 120 request/minute.
</Notice>
</section>
<section class="api_page">
<h1>Get Jokes</h1>
<h2>Get single random joke</h2>
<p>You'll get different result for every call.</p>
<Codeblock>
GET {import.meta.env.BROWSER_API_ENDPOINT}/
</Codeblock>
<h2>Get today's joke</h2>
<p>A joke a day makes more of a dad out of you.</p>
<Codeblock>
GET {import.meta.env.BROWSER_API_ENDPOINT}/today
</Codeblock>
<h2>Get joke by ID</h2>
<p>You'll get consistent joke for every call with the same ID. Where ID is a number ranging from 1 to {total}.</p>
<Codeblock>
GET {import.meta.env.BROWSER_API_ENDPOINT}/id/&lcub;id&rcub;
</Codeblock>
<h2>Get total number of jokes</h2>
<p>...in a form of JSON response.</p>
<Codeblock>
GET {import.meta.env.BROWSER_API_ENDPOINT}/total
</Codeblock>
</section>
<style>
h1 {
@apply text-4xl;
@apply font-bold;
@apply py-4;
}
h2 {
@apply text-2xl;
@apply font-bold;
@apply pt-6;
@apply pb-1;
}
p {
@apply text-base;
@apply opacity-80;
@apply py-2;
}
</style>
</Layout>

View File

@ -0,0 +1,80 @@
---
import Codeblock from '../../components/Codeblock.astro';
import Layout from '../../layout/Layout.astro';
// This page is meant to guide people on how to use the API.
const browserAPIEndpoint = import.meta.env.BROWSER_API_ENDPOINT;
---
<!-- <svelte:head>
<title>{$_('navigation.guide')} - {$_('meta.title')}</title>
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/guide" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head> -->
<Layout>
<section class="guide_page">
<h1>Guide</h1>
<p>
To access the API, there are a few ways to do it.
It depends on what you are trying to accomplish with it.
</p>
</section>
<section class="guide_page">
<h2>Direct request with <code>&lt;img&gt;</code> block</h2>
<Codeblock>&lt;img src="{browserAPIEndpoint}/" /&gt;</Codeblock>
</section>
<section class="guide_page">
<h2>Using fetch API</h2>
<p>You can use it, but I personally don't recommend it.</p>
<Codeblock>
const response = await fetch(&quot;{browserAPIEndpoint}/&quot;);<br />
<br />
if (!response.ok) &#123;<br />
&nbsp;&nbsp;// Do some error handling if the request fails<br />
&#125;<br />
<br />
const blob = await response.blob();<br />
<br />
const objectURL = URL.createObjectURL(blob);<br />
<br />
&lt;img src=&quot;&#123; objectURL &#125;&quot; /&gt;
</Codeblock>
</section>
<style>
p {
@apply text-base;
@apply py-2;
@apply lg\:w-2\/3;
}
h1 {
@apply text-4xl;
@apply font-bold;
@apply py-2;
}
h2 {
@apply text-2xl;
@apply font-bold;
@apply py-2;
}
a {
@apply hover\:underline;
@apply dark\:text-dodger-200;
@apply text-dodger-700;
}
section {
@apply pt-6;
}
</style>
</Layout>

View File

@ -0,0 +1,44 @@
---
import Codeblock from '../../components/Codeblock.astro';
import Layout from '../../layout/Layout.astro';
async function load() {
const response = await fetch(`${import.meta.env.SERVER_API_ENDPOINT}/total`, {
method: 'GET',
});
const responseBody = await response.json();
return {
total: responseBody.message,
};
}
/** @type {import('./$types').PageData} */
export let data;
let { total } = await load();
---
<Layout lang="en">
<section>
<div class="flex flex-col lg:flex-row items-center py-8">
<div class="flex-1">
<h1 class="text-4xl sm:text-5xl md:text-6xl font-bold py-2">{$_('meta.tagline-total', { values: { total } })}</h1>
<p class="text-base py-4 md:w-2/3">{$_('meta.explanation')}</p>
</div>
<div class="flex-1 md:px-6 w-full">
<div class="max-w-xs mx-auto">
<img alt="Sample joke" class="py-6 shadow-2xl" src={env.BROWSER_API_ENDPOINT + `/today`} />
</div>
<Codeblock>$ curl -XGET 'https://jokesbapak2.reinaldyrafli.com/api/'</Codeblock>
<p class="text-sm text-center py-4 opacity-70 hover:opacity-100 transition duration-300 ease-in-out">
{$_('home.more.1')}
<span class="hover:underline cursor-pointer" on:click={() => goto('/guide')}>{$_('navigation.guide')}</span>
{$_('home.more.2')}
<span class="hover:underline cursor-pointer" on:click={() => goto('/api')}>{$_('navigation.api')}</span>
</p>
</div>
</div>
</section>
</Layout>

View File

@ -0,0 +1,71 @@
---
import Layout from "../../layout/Layout.astro";
---
<!-- <svelte:head>
<title>{$_('navigation.why')} - {$_('meta.title')}</title>
<meta content={$_('navigation.why') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.why') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.why') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/why" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head> -->
<Layout>
<section class="why_page">
<h1 id="why-does-this-project-exists">{$_('why.exists.title')}</h1>
<p>{$_('why.exists.body.1')} {$_('why.exists.body.2')} {$_('why.exists.body.3')} {$_('why.exists.body.4')}</p>
<p>{$_('why.exists.body.5')} {$_('why.exists.body.6')}</p>
</section>
<section class="why_page">
<h1 id="can-i-submit-my-dad-joke">{$_('why.submit.title')}</h1>
<p>
{$_('why.submit.body.1')}
{$_('why.submit.body.2')}
<a href="mailto:aldy505@proton.me">{$_('why.submit.body.3')}</a>
{$_('why.submit.body.4')}
{$_('why.submit.body.5')}
{$_('why.submit.body.6')}
</p>
</section>
<section class="why_page">
<h1 id="can-i-contribute">{$_('why.contribute.title')}</h1>
<p>
{$_('why.contribute.body.1')}
{$_('why.contribute.body.2')}
<a href="https://www.github.com/aldy505/jokes-bapak2">{$_('why.contribute.body.3')}</a>
{$_('why.contribute.body.4')}
</p>
</section>
<section class="why_page">
<h1 id="other-inquiries">{$_('why.inquiries.title')}</h1>
<p>
{$_('why.inquiries.body.1')}
<a href="mailto:aldy505@proton.me">{$_('why.inquiries.body.2')}</a>, {$_('why.inquiries.body.3')}
</p>
</section>
<style>
p {
@apply text-base;
@apply py-2;
@apply lg\:w-2\/3;
}
h1 {
@apply text-3xl;
@apply font-bold;
@apply py-2;
}
a {
@apply hover\:underline;
@apply dark\:text-dodger-200;
@apply text-dodger-700;
}
section {
@apply pt-6;
}
</style>
</Layout>

View File

@ -0,0 +1,77 @@
---
// This page is meant to explain available API endpoints.
import Codeblock from '../../components/Codeblock.astro';
import Notice from '../../components/Notice.astro';
import Layout from '../../layout/Layout.astro';
const totalJokes = async (): Promise<string> => {
const response = await fetch(`${import.meta.env.API_ENDPOINT}/total`);
const responseBody = await response.json();
return responseBody.message;
};
let total = await totalJokes();
---
<!-- <svelte:head>
<title>{$_('navigation.api')} - {$_('meta.title')}</title>
<meta content={$_('navigation.api') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.api') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.api') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/api" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head> -->
<Layout>
<section>
<Notice emoji="💡">
{$_('api.limit')}
</Notice>
</section>
<section class="api_page">
<h1>{$_('api.get.title')}</h1>
<h2>{$_('api.get.random.title')}</h2>
<p>{$_('api.get.random.body')}</p>
<Codeblock>
GET {import.meta.env.BROWSER_API_ENDPOINT}/
</Codeblock>
<h2>{$_('api.get.today.title')}</h2>
<p>{$_('api.get.today.body')}</p>
<Codeblock>
GET {import.meta.env.BROWSER_API_ENDPOINT}/today
</Codeblock>
<h2>{$_('api.get.id.title')}</h2>
<p>{$_('api.get.id.body', { values: { total } })}</p>
<Codeblock>
GET {import.meta.env.BROWSER_API_ENDPOINT}/id/&lcub;id&rcub;
</Codeblock>
<h2>{$_('api.get.total.title')}</h2>
<p>{$_('api.get.total.body')}</p>
<Codeblock>
GET {import.meta.env.BROWSER_API_ENDPOINT}/total
</Codeblock>
</section>
<style>
h1 {
@apply text-4xl;
@apply font-bold;
@apply py-4;
}
h2 {
@apply text-2xl;
@apply font-bold;
@apply pt-6;
@apply pb-1;
}
p {
@apply text-base;
@apply opacity-80;
@apply py-2;
}
</style>
</Layout>

View File

@ -0,0 +1,81 @@
---
import Codeblock from '../../components/Codeblock.astro';
import { _ } from 'svelte-i18n';
import env from '$lib/env';
import Layout from '../../layout/Layout.astro';
// This page is meant to guide people on how to use the API.
---
<!-- <svelte:head>
<title>{$_('navigation.guide')} - {$_('meta.title')}</title>
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/guide" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head> -->
<Layout>
<section class="guide_page">
<h1>{$_('navigation.guide')}</h1>
<p>
{$_('guide.introduction.1')}
{$_('guide.introduction.2')}
</p>
</section>
<section class="guide_page">
<h2>{$_('guide.direct.1')} <code>&lt;img&gt;</code> {$_('guide.direct.2')}</h2>
<Codeblock>&lt;img src="{env.BROWSER_API_ENDPOINT}/" /&gt;</Codeblock>
</section>
<section class="guide_page">
<h2>{$_('guide.fetch.1')}</h2>
<p>{$_('guide.fetch.2')}</p>
<Codeblock>
const response = await fetch(&quot;{env.BROWSER_API_ENDPOINT}/&quot;);<br />
<br />
if (!response.ok) &#123;<br />
&nbsp;&nbsp;// {$_('guide.fetch.3')}<br />
&#125;<br />
<br />
const blob = await response.blob();<br />
<br />
const objectURL = URL.createObjectURL(blob);<br />
<br />
&lt;img src=&quot;&#123; objectURL &#125;&quot; /&gt;
</Codeblock>
</section>
<style>
p {
@apply text-base;
@apply py-2;
@apply lg\:w-2\/3;
}
h1 {
@apply text-4xl;
@apply font-bold;
@apply py-2;
}
h2 {
@apply text-2xl;
@apply font-bold;
@apply py-2;
}
a {
@apply hover\:underline;
@apply dark\:text-dodger-200;
@apply text-dodger-700;
}
section {
@apply pt-6;
}
</style>
</Layout>

View File

@ -0,0 +1,44 @@
---
import Codeblock from '../../components/Codeblock.astro';
import Layout from '../../layout/Layout.astro';
async function load() {
const response = await fetch(`${import.meta.env.SERVER_API_ENDPOINT}/total`, {
method: 'GET',
});
const responseBody = await response.json();
return {
total: responseBody.message,
};
}
/** @type {import('./$types').PageData} */
export let data;
let { total } = await load();
---
<Layout lang="en">
<section>
<div class="flex flex-col lg:flex-row items-center py-8">
<div class="flex-1">
<h1 class="text-4xl sm:text-5xl md:text-6xl font-bold py-2">{$_('meta.tagline-total', { values: { total } })}</h1>
<p class="text-base py-4 md:w-2/3">{$_('meta.explanation')}</p>
</div>
<div class="flex-1 md:px-6 w-full">
<div class="max-w-xs mx-auto">
<img alt="Sample joke" class="py-6 shadow-2xl" src={env.BROWSER_API_ENDPOINT + `/today`} />
</div>
<Codeblock>$ curl -XGET 'https://jokesbapak2.reinaldyrafli.com/api/'</Codeblock>
<p class="text-sm text-center py-4 opacity-70 hover:opacity-100 transition duration-300 ease-in-out">
{$_('home.more.1')}
<span class="hover:underline cursor-pointer" on:click={() => goto('/guide')}>{$_('navigation.guide')}</span>
{$_('home.more.2')}
<span class="hover:underline cursor-pointer" on:click={() => goto('/api')}>{$_('navigation.api')}</span>
</p>
</div>
</div>
</section>
</Layout>

View File

@ -0,0 +1,71 @@
---
import Layout from "../../layout/Layout.astro";
---
<!-- <svelte:head>
<title>{$_('navigation.why')} - {$_('meta.title')}</title>
<meta content={$_('navigation.why') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.why') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.why') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/why" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head> -->
<Layout>
<section class="why_page">
<h1 id="why-does-this-project-exists">{$_('why.exists.title')}</h1>
<p>{$_('why.exists.body.1')} {$_('why.exists.body.2')} {$_('why.exists.body.3')} {$_('why.exists.body.4')}</p>
<p>{$_('why.exists.body.5')} {$_('why.exists.body.6')}</p>
</section>
<section class="why_page">
<h1 id="can-i-submit-my-dad-joke">{$_('why.submit.title')}</h1>
<p>
{$_('why.submit.body.1')}
{$_('why.submit.body.2')}
<a href="mailto:aldy505@proton.me">{$_('why.submit.body.3')}</a>
{$_('why.submit.body.4')}
{$_('why.submit.body.5')}
{$_('why.submit.body.6')}
</p>
</section>
<section class="why_page">
<h1 id="can-i-contribute">{$_('why.contribute.title')}</h1>
<p>
{$_('why.contribute.body.1')}
{$_('why.contribute.body.2')}
<a href="https://www.github.com/aldy505/jokes-bapak2">{$_('why.contribute.body.3')}</a>
{$_('why.contribute.body.4')}
</p>
</section>
<section class="why_page">
<h1 id="other-inquiries">{$_('why.inquiries.title')}</h1>
<p>
{$_('why.inquiries.body.1')}
<a href="mailto:aldy505@proton.me">{$_('why.inquiries.body.2')}</a>, {$_('why.inquiries.body.3')}
</p>
</section>
<style>
p {
@apply text-base;
@apply py-2;
@apply lg\:w-2\/3;
}
h1 {
@apply text-3xl;
@apply font-bold;
@apply py-2;
}
a {
@apply hover\:underline;
@apply dark\:text-dodger-200;
@apply text-dodger-700;
}
section {
@apply pt-6;
}
</style>
</Layout>

View File

@ -0,0 +1 @@
<meta http-equiv="refresh" content="0;url=/en/" />

View File

@ -1,19 +0,0 @@
<script context="module" lang="ts">
import type { ErrorLoad } from '@sveltejs/kit';
import Sentry from '$lib/logging';
export const load: ErrorLoad = ({ error }) => {
Sentry.captureException(error);
return {};
};
</script>
<script lang="ts">
import { goto } from '$app/navigation';
import { _ } from 'svelte-i18n';
</script>
<section>
<h1 class="text-5xl font-bold">{$_('error.heading')}</h1>
<p class="text-base" on:click={() => goto('/')}>{$_('error.homepage')}</p>
</section>

View File

@ -1,55 +0,0 @@
<script context="module" lang="ts">
import '$lib/locale';
</script>
<script lang="ts">
import '@fontsource/fira-mono';
import '@fontsource/rubik';
import { _ } from 'svelte-i18n';
import Navbar from '../components/navbar.svelte';
</script>
<svelte:head>
<meta content={$_('meta.title')} property="og:site_name" />
</svelte:head>
<div
class="bg-gradient-to-br from-transparent to-lavender-300 dark:(bg-gray-900 to-lavender-900 text-white) min-h-screen h-full w-full"
>
<div class="container mx-auto xl:px-40 lg:px-28 md:px-20 sm:px-12 px-8 w-full">
<header>
<Navbar />
</header>
<main class="font-body">
<slot />
</main>
<footer class="font-body py-8 w-full md:w-1/2 lg:w-2/5">
<div class="flex flex-col md:flex-row flex-wrap">
<div class="flex-initial pr-3">
<p class="text-sm opacity-50 hover:opacity-90 transition duration-300 ease-in-out inline-block">
{$_('footer.made')} <span class="text-red-500">&#10084;</span>
{$_('footer.indonesia')}.
</p>
</div>
<div class="flex-initial pr-3">
<p class="text-sm opacity-50 hover:opacity-90 transition duration-300 ease-in-out inline-block">
{$_('footer.available')}
<a class="hover:underline" href="https://www.github.com/aldy505/jokes-bapak2">{$_('footer.github')}</a>.
</p>
</div>
<div class="flex-initial pr-3">
<p class="text-sm opacity-50 hover:opacity-90 transition duration-300 ease-in-out inline-block">
{$_('footer.language')}
<a class="hover:underline" href="?lang=en" target="_top">{$_('footer.english')}</a>
|
<a class="hover:underline" href="?lang=id" target="_top">{$_('footer.indonesian')}</a>.
</p>
</div>
</div>
</footer>
</div>
</div>
<style windi:global windi:preflights:global windi:safelist:global>
</style>

View File

@ -1,19 +0,0 @@
import { $fetch } from 'ohmyfetch';
import env from '../lib/env';
interface TotalResponse {
message: number;
}
/** @type {import('./$types').PageServerLoad} */
export async function load() {
const response = await $fetch<TotalResponse>('total', {
method: 'GET',
baseURL: env.SERVER_API_ENDPOINT,
parseResponse: JSON.parse,
});
return {
total: response.message,
};
}

View File

@ -1,43 +0,0 @@
<script lang="ts">
import { _ } from 'svelte-i18n';
import { goto } from '$app/navigation';
import env from '$lib/env';
import Codeblock from '../components/codeblock.svelte';
/** @type {import('./$types').PageData} */
export let data;
let total = data.total;
</script>
<svelte:head>
<title>{$_('meta.title')} - {$_('meta.tagline')}</title>
<meta content={$_('meta.title') + '-' + $_('meta.tagline')} name="title" />
<meta content={$_('meta.title') + '-' + $_('meta.tagline')} name="twitter:title" />
<meta content={$_('meta.title') + '-' + $_('meta.tagline')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head>
<section>
<div class="flex flex-col lg:flex-row items-center py-8">
<div class="flex-1">
<h1 class="text-4xl sm:text-5xl md:text-6xl font-bold py-2">{$_('meta.tagline-total', { values: { total } })}</h1>
<p class="text-base py-4 md:w-2/3">{$_('meta.explanation')}</p>
</div>
<div class="flex-1 md:px-6 w-full">
<div class="max-w-xs mx-auto">
<img alt="Sample joke" class="py-6 shadow-2xl" src={env.BROWSER_API_ENDPOINT + `/today`} />
</div>
<Codeblock>$ curl -XGET 'https://jokesbapak2.reinaldyrafli.com/api/'</Codeblock>
<p class="text-sm text-center py-4 opacity-70 hover:opacity-100 transition duration-300 ease-in-out">
{$_('home.more.1')}
<span class="hover:underline cursor-pointer" on:click={() => goto('/guide')}>{$_('navigation.guide')}</span>
{$_('home.more.2')}
<span class="hover:underline cursor-pointer" on:click={() => goto('/api')}>{$_('navigation.api')}</span>
</p>
</div>
</div>
</section>

View File

@ -1 +0,0 @@
export const ssr = true;

View File

@ -1,86 +0,0 @@
<script lang="ts">
// This page is meant to explain available API endpoints.
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import env from '$lib/env';
import { $fetch as omf } from 'ohmyfetch';
import Codeblock from '../../components/codeblock.svelte';
import Notice from '../../components/notice.svelte';
interface TotalResponse {
message: string;
}
let total;
onMount(async () => {
const totalJokes = async (): Promise<string> => {
const response = await omf<TotalResponse>(`${env.API_ENDPOINT}/total`);
return response.message;
};
total = await totalJokes();
});
</script>
<svelte:head>
<title>{$_('navigation.api')} - {$_('meta.title')}</title>
<meta content={$_('navigation.api') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.api') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.api') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/api" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head>
<section>
<Notice emoji="💡">
{$_('api.limit')}
</Notice>
</section>
<section class="api_page">
<h1>{$_('api.get.title')}</h1>
<h2>{$_('api.get.random.title')}</h2>
<p>{$_('api.get.random.body')}</p>
<Codeblock>
GET {env.BROWSER_API_ENDPOINT}/
</Codeblock>
<h2>{$_('api.get.today.title')}</h2>
<p>{$_('api.get.today.body')}</p>
<Codeblock>
GET {env.BROWSER_API_ENDPOINT}/today
</Codeblock>
<h2>{$_('api.get.id.title')}</h2>
<p>{$_('api.get.id.body', { values: { total } })}</p>
<Codeblock>
GET {env.BROWSER_API_ENDPOINT}/id/&lcub;id&rcub;
</Codeblock>
<h2>{$_('api.get.total.title')}</h2>
<p>{$_('api.get.total.body')}</p>
<Codeblock>
GET {env.BROWSER_API_ENDPOINT}/total
</Codeblock>
</section>
<style>
h1 {
@apply text-4xl;
@apply font-bold;
@apply py-4;
}
h2 {
@apply text-2xl;
@apply font-bold;
@apply pt-6;
@apply pb-1;
}
p {
@apply text-base;
@apply opacity-80;
@apply py-2;
}
</style>

View File

@ -1,78 +0,0 @@
<script lang="ts">
import Codeblock from '../../components/codeblock.svelte';
import { _ } from 'svelte-i18n';
import env from '$lib/env';
// This page is meant to guide people on how to use the API.
</script>
<svelte:head>
<title>{$_('navigation.guide')} - {$_('meta.title')}</title>
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.guide') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/guide" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head>
<section class="guide_page">
<h1>{$_('navigation.guide')}</h1>
<p>
{$_('guide.introduction.1')}
{$_('guide.introduction.2')}
</p>
</section>
<section class="guide_page">
<h2>{$_('guide.direct.1')} <code>&lt;img&gt;</code> {$_('guide.direct.2')}</h2>
<Codeblock>&lt;img src="{env.BROWSER_API_ENDPOINT}/" /&gt;</Codeblock>
</section>
<section class="guide_page">
<h2>{$_('guide.fetch.1')}</h2>
<p>{$_('guide.fetch.2')}</p>
<Codeblock>
const response = await fetch(&quot;{env.BROWSER_API_ENDPOINT}/&quot;);<br />
<br />
if (!response.ok) &#123;<br />
&nbsp;&nbsp;// {$_('guide.fetch.3')}<br />
&#125;<br />
<br />
const blob = await response.blob();<br />
<br />
const objectURL = URL.createObjectURL(blob);<br />
<br />
&lt;img src=&quot;&#123; objectURL &#125;&quot; /&gt;
</Codeblock>
</section>
<style>
p {
@apply text-base;
@apply py-2;
@apply lg\:w-2\/3;
}
h1 {
@apply text-4xl;
@apply font-bold;
@apply py-2;
}
h2 {
@apply text-2xl;
@apply font-bold;
@apply py-2;
}
a {
@apply hover\:underline;
@apply dark\:text-dodger-200;
@apply text-dodger-700;
}
section {
@apply pt-6;
}
</style>

View File

@ -1,71 +0,0 @@
<script lang="ts">
import { _ } from 'svelte-i18n';
</script>
<svelte:head>
<title>{$_('navigation.why')} - {$_('meta.title')}</title>
<meta content={$_('navigation.why') + '-' + $_('meta.title')} name="title" />
<meta content={$_('navigation.why') + '-' + $_('meta.title')} name="twitter:title" />
<meta content={$_('navigation.why') + '-' + $_('meta.title')} property="og:title" />
<link href="https://jokesbapak2.reinaldyrafli.com/why" rel="canonical" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" name="twitter:description" />
<meta content="Largest collection of Indonesian dad jokes as a consumable API" property="og:description" />
</svelte:head>
<section class="why_page">
<h1 id="why-does-this-project-exists">{$_('why.exists.title')}</h1>
<p>{$_('why.exists.body.1')} {$_('why.exists.body.2')} {$_('why.exists.body.3')} {$_('why.exists.body.4')}</p>
<p>{$_('why.exists.body.5')} {$_('why.exists.body.6')}</p>
</section>
<section class="why_page">
<h1 id="can-i-submit-my-dad-joke">{$_('why.submit.title')}</h1>
<p>
{$_('why.submit.body.1')}
{$_('why.submit.body.2')}
<a href="mailto:aldy505@tutanota.com">{$_('why.submit.body.3')}</a>
{$_('why.submit.body.4')}
{$_('why.submit.body.5')}
{$_('why.submit.body.6')}
</p>
</section>
<section class="why_page">
<h1 id="can-i-contribute">{$_('why.contribute.title')}</h1>
<p>
{$_('why.contribute.body.1')}
{$_('why.contribute.body.2')}
<a href="https://www.github.com/aldy505/jokes-bapak2">{$_('why.contribute.body.3')}</a>
{$_('why.contribute.body.4')}
</p>
</section>
<section class="why_page">
<h1 id="other-inquiries">{$_('why.inquiries.title')}</h1>
<p>
{$_('why.inquiries.body.1')}
<a href="mailto:aldy505@tutanota.com">{$_('why.inquiries.body.2')}</a>, {$_('why.inquiries.body.3')}
</p>
</section>
<style>
p {
@apply text-base;
@apply py-2;
@apply lg\:w-2\/3;
}
h1 {
@apply text-3xl;
@apply font-bold;
@apply py-2;
}
a {
@apply hover\:underline;
@apply dark\:text-dodger-200;
@apply text-dodger-700;
}
section {
@apply pt-6;
}
</style>

3
client/src/tsconfig.json Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/strict"
}

View File

@ -1,35 +0,0 @@
import { vitePreprocess } from '@sveltejs/kit/vite';
import adapter from '@sveltejs/adapter-node';
import { windi } from 'svelte-windicss-preprocess';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: [
windi({
configPath: './windi.config.ts',
preflights: false,
}),
vitePreprocess({ postcss: false }),
],
kit: {
// hydrate the <div id="svelte"> element in src/app.html
trailingSlash: 'never',
files: {
routes: './src/routes',
assets: './static',
hooks: {
server: './src',
client: './src',
},
lib: './src/lib',
},
adapter: adapter({
out: 'dist',
}),
},
};
export default config;

View File

@ -1,32 +0,0 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"moduleResolution": "node",
"module": "es2020",
"lib": ["es2020"],
"target": "es2019",
/**
svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
to enforce using \`import type\` instead of \`import\` for Types.
*/
"importsNotUsedAsValues": "error",
"isolatedModules": true,
"resolveJsonModule": true,
/**
To have warnings/errors of the Svelte compiler at the correct position,
enable source maps by default.
*/
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"allowJs": true,
"checkJs": true,
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
}

View File

@ -1,4 +1,4 @@
import { defineConfig } from 'windicss/helpers';
import { defineConfig } from 'unocss';
export default defineConfig({
darkMode: 'media',

View File

@ -1,6 +0,0 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
});