feat: initialize dating site

This commit is contained in:
2026-06-21 22:23:38 +07:00
commit 84bdb135d9
30 changed files with 2820 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
name: Deploy to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Check
run: pnpm run check
- name: Build
env:
BASE_PATH: /${{ github.event.repository.name }}
run: pnpm run build
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v4
with:
path: build
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
+23
View File
@@ -0,0 +1,23 @@
node_modules
# Output
.output
.vercel
.netlify
.wrangler
/.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
View File
@@ -0,0 +1 @@
engine-strict=true
+9
View File
@@ -0,0 +1,9 @@
# Package Managers
package-lock.json
pnpm-lock.yaml
yarn.lock
bun.lock
bun.lockb
# Miscellaneous
/static/
+15
View File
@@ -0,0 +1,15 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [
{
"files": "*.svelte",
"options": {
"parser": "svelte"
}
}
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"recommendations": ["svelte.svelte-vscode", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
}
+51
View File
@@ -0,0 +1,51 @@
# Dating
Warm-witty dating JD and CV site for Tien Nguyen Minh.
## Pages
- `/` home
- `/jd/` future lover job description
- `/cv/` candidate CV
## Tech
- SvelteKit 2
- Svelte 5
- TypeScript
- `@sveltejs/adapter-static`
- GitHub Pages
## Developing
Install dependencies:
```sh
pnpm install
```
Run locally:
```sh
pnpm run dev
```
## Building
Local static build:
```sh
pnpm run build
```
GitHub Pages build:
```sh
pnpm run build:gh
```
Preview:
```sh
pnpm run preview
```
+31
View File
@@ -0,0 +1,31 @@
# Deployment
## Platform
GitHub Pages.
## Production URL
Expected URL: `https://tiennm99.github.io/dating/`.
## Build
```sh
pnpm run build
```
For project-page base path:
```sh
pnpm run build:gh
```
## Workflow
`.github/workflows/deploy-pages.yml` builds on `main`, uploads `build/`, then deploys with GitHub Pages Actions.
## Notes
- Static SvelteKit only. No backend, no form service.
- Pages source should be GitHub Actions.
- No secrets required.
+41
View File
@@ -0,0 +1,41 @@
import prettier from 'eslint-config-prettier';
import path from 'node:path';
import js from '@eslint/js';
import svelte from 'eslint-plugin-svelte';
import { defineConfig, includeIgnoreFile } from 'eslint/config';
import globals from 'globals';
import ts from 'typescript-eslint';
const gitignorePath = path.resolve(import.meta.dirname, '.gitignore');
export default defineConfig(
includeIgnoreFile(gitignorePath),
js.configs.recommended,
ts.configs.recommended,
svelte.configs.recommended,
prettier,
svelte.configs.prettier,
{
languageOptions: { globals: { ...globals.browser, ...globals.node } },
rules: {
// typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects.
// see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
'no-undef': 'off'
}
},
{
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
languageOptions: {
parserOptions: {
projectService: true,
extraFileExtensions: ['.svelte'],
parser: ts.parser
}
}
},
{
// Override or add rule settings here, such as:
// 'svelte/button-has-type': 'error'
rules: {}
}
);
+35
View File
@@ -0,0 +1,35 @@
{
"name": "dating",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"build:gh": "BUILD_PROFILE=gh vite build",
"preview": "vite preview",
"prepare": "svelte-kit sync || echo ''",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.63.0",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"@types/node": "^24",
"eslint": "^10.4.1",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.19.0",
"globals": "^17.6.0",
"prettier": "^3.8.3",
"prettier-plugin-svelte": "^4.1.0",
"svelte": "^5.56.1",
"svelte-check": "^4.6.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.60.1",
"vite": "^8.0.16"
}
}
+1826
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
allowBuilds:
esbuild: true
+3
View File
@@ -0,0 +1,3 @@
@import './lib/styles/base.css';
@import './lib/styles/layout.css';
@import './lib/styles/content.css';
+13
View File
@@ -0,0 +1,13 @@
// See https://svelte.dev/docs/kit/types#app.d.ts
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}
export {};
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="text-scale" content="scale" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
+17
View File
@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
<title>Dating JD &amp; CV</title>
<rect width="128" height="128" rx="64" fill="#1d2930" />
<circle cx="64" cy="64" r="48" fill="#f7f4ed" />
<path d="M33 66c19-25 43-25 62 0-19 24-43 24-62 0Z" fill="#9d3f45" opacity=".92" />
<text
x="64"
y="74"
text-anchor="middle"
font-family="Georgia, serif"
font-size="34"
font-weight="700"
fill="#f7f4ed"
>
TN
</text>
</svg>

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

+1
View File
@@ -0,0 +1 @@
// place files you want to import through the `$lib` alias in this folder.
+47
View File
@@ -0,0 +1,47 @@
export const roleBenefits = [
'Priority support for hard days, strange ideas, and quiet evenings.',
'Consistent honesty, clear communication, and bug reports without blame.',
'A partner who can debug production systems and also overthink dinner choices.',
'Long-term growth plan: better health, better travel, better stories.'
];
export const roleResponsibilities = [
'Build trust with direct words and small repeated actions.',
'Respect alone time, career ambition, family, friends, and personal rituals.',
'Bring curiosity, kindness, and willingness to repair after conflict.',
'Co-maintain a life where both people can be serious and silly.'
];
export const niceToHave = [
'Enjoys food, walks, games, films, or learning obscure things for no urgent reason.',
'Can laugh at a corporate parody without turning love into a quarterly OKR.',
'Believes romance works better with patience than guessing games.'
];
export const cvStrengths = [
{
title: 'Reliable under load',
body: 'Senior Software Engineer at ZingPlay Game Studios, VNG Corp., with 5+ years building and operating real-time multiplayer game backends.'
},
{
title: 'Builder mindset',
body: 'Comfortable turning vague ideas into running systems with Java, Go, TypeScript, Docker, CI, and a lot of practical debugging.'
},
{
title: 'Long-game thinker',
body: 'Maintains production systems, tests release-critical flows, and prefers durable fixes over dramatic hot takes.'
},
{
title: 'Still improving',
body: 'Active curriculum includes clearer communication, better routines, deeper empathy, and remembering that rest is also a feature.'
}
];
export const cvFacts = [
['Current role', 'Senior Software Engineer'],
['Main craft', 'Backend systems for multiplayer games'],
['Languages', 'Java, Go, TypeScript, Shell'],
['Location', 'Ho Chi Minh City, Vietnam'],
['Education', 'Computer Science and Engineering, HCMUT'],
['Relationship mode', 'Static site first, real conversation later']
] as const;
+87
View File
@@ -0,0 +1,87 @@
@import url('https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400;500;600;700&family=Fraunces:opsz,wght@9..144,500;9..144,650;9..144,750&display=swap');
:root {
font-family: 'Be Vietnam Pro', 'Segoe UI', sans-serif;
color: #1d2930;
background: #eef1ee;
--ink: #1d2930;
--paper: #f7f4ed;
--mist: #dfe8e2;
--sage: #637f74;
--oxblood: #9d3f45;
--brass: #c7964f;
--blueprint: #415f6b;
--line: rgba(29, 41, 48, 0.16);
--shadow: 0 24px 70px rgba(29, 41, 48, 0.14);
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
min-width: 320px;
background:
radial-gradient(circle at 12% 0%, rgba(99, 127, 116, 0.18), transparent 30rem),
linear-gradient(120deg, #eef1ee 0%, #f7f4ed 54%, #e4ece8 100%);
color: var(--ink);
}
a {
color: inherit;
text-decoration-thickness: 0.08em;
text-underline-offset: 0.24em;
}
a:focus-visible {
outline: 3px solid var(--brass);
outline-offset: 4px;
}
h1,
h2,
h3 {
font-family: 'Fraunces', Georgia, serif;
letter-spacing: 0;
line-height: 0.98;
}
h1 {
max-width: 11ch;
margin: 0;
font-size: clamp(3.4rem, 11vw, 8.8rem);
}
h2 {
margin: 0 0 1rem;
font-size: clamp(2rem, 5vw, 4.8rem);
}
h3 {
margin: 0 0 0.75rem;
font-size: clamp(1.35rem, 3vw, 2.1rem);
}
p {
line-height: 1.7;
}
ul {
margin: 0;
padding-left: 1.25rem;
}
li + li {
margin-top: 0.65rem;
}
@media (max-width: 720px) {
h1 {
font-size: clamp(3rem, 18vw, 5rem);
}
}
+102
View File
@@ -0,0 +1,102 @@
.eyebrow {
margin: 0 0 1rem;
color: var(--oxblood);
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.lead {
max-width: 42rem;
font-size: clamp(1.1rem, 2vw, 1.35rem);
}
.button-row {
display: flex;
flex-wrap: wrap;
gap: 0.8rem;
margin-top: 2rem;
}
.button {
min-height: 48px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.85rem 1.1rem;
border: 1px solid var(--ink);
background: var(--ink);
color: white;
font-weight: 700;
text-decoration: none;
transition:
transform 180ms ease,
background 180ms ease;
}
.button:hover {
transform: translateY(-2px);
background: var(--oxblood);
}
.button.secondary {
background: transparent;
color: var(--ink);
}
.page-section {
padding-block: clamp(3rem, 8vw, 6.5rem);
}
.section-grid {
display: grid;
grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.4fr);
gap: clamp(2rem, 7vw, 6rem);
align-items: start;
}
.panel-list {
display: grid;
gap: 1rem;
}
.panel {
border-left: 4px solid var(--sage);
background: rgba(247, 244, 237, 0.76);
padding: clamp(1.1rem, 3vw, 1.6rem);
box-shadow: 0 1px 0 var(--line);
}
.panel.strong {
border-color: var(--oxblood);
box-shadow: var(--shadow);
}
.meta-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 1px;
margin-top: 2rem;
background: var(--line);
}
.meta-grid > div {
background: rgba(247, 244, 237, 0.82);
padding: 1rem;
}
.meta-grid span {
display: block;
color: var(--blueprint);
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
}
@media (max-width: 720px) {
.section-grid,
.meta-grid {
grid-template-columns: 1fr;
}
}
+76
View File
@@ -0,0 +1,76 @@
.skip-link {
position: fixed;
left: 1rem;
top: 1rem;
z-index: 20;
transform: translateY(-140%);
background: var(--ink);
color: white;
padding: 0.75rem 1rem;
}
.skip-link:focus {
transform: translateY(0);
}
.site-shell {
width: min(1120px, calc(100% - 32px));
margin-inline: auto;
}
.site-header {
position: sticky;
top: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding-block: 1rem;
backdrop-filter: blur(18px);
}
.brand-mark,
nav {
display: flex;
align-items: center;
gap: 0.8rem;
}
.brand-mark {
font-weight: 700;
text-decoration: none;
}
.brand-seal {
display: grid;
width: 2.25rem;
height: 2.25rem;
place-items: center;
border: 1px solid var(--line);
border-radius: 50%;
background: var(--paper);
color: var(--oxblood);
font-family: 'Fraunces', Georgia, serif;
}
nav a {
min-height: 44px;
display: inline-flex;
align-items: center;
border-bottom: 1px solid transparent;
font-size: 0.95rem;
font-weight: 600;
text-decoration: none;
}
nav a:hover {
border-color: currentColor;
}
@media (max-width: 720px) {
.site-header {
align-items: flex-start;
flex-direction: column;
}
}
+36
View File
@@ -0,0 +1,36 @@
<script lang="ts">
import { resolve } from '$app/paths';
import favicon from '$lib/assets/favicon.svg';
import '../app.css';
let { children } = $props();
const navItems = [
{ href: resolve('/'), label: 'Home' },
{ href: resolve('/jd/'), label: 'JD' },
{ href: resolve('/cv/'), label: 'CV' }
];
</script>
<svelte:head>
<link rel="icon" href={favicon} />
</svelte:head>
<a class="skip-link" href="#content">Skip to content</a>
<header class="site-shell site-header">
<a class="brand-mark" href={resolve('/')} aria-label="Dating JD & CV home">
<span class="brand-seal">TN</span>
<span>Dating JD & CV</span>
</a>
<nav aria-label="Primary navigation">
{#each navItems as item (item.href)}
<a href={item.href}>{item.label}</a>
{/each}
</nav>
</header>
<main id="content">
{@render children()}
</main>
+2
View File
@@ -0,0 +1,2 @@
export const prerender = true;
export const trailingSlash = 'always';
+84
View File
@@ -0,0 +1,84 @@
<script lang="ts">
import { resolve } from '$app/paths';
import heroImage from '$lib/assets/offer-letter-hero.png';
</script>
<svelte:head>
<title>Tien Nguyen Minh | Dating JD & CV</title>
<meta
name="description"
content="A warm-witty dating job description and CV for Tien Nguyen Minh."
/>
</svelte:head>
<section
class="home-hero"
style={`background-image: linear-gradient(90deg, rgba(29, 41, 48, 0.84), rgba(29, 41, 48, 0.48), rgba(29, 41, 48, 0.1)), url(${heroImage});`}
>
<div class="site-shell hero-copy">
<p class="eyebrow">Open role / long-term partner</p>
<h1>Tien Nguyen Minh</h1>
<p class="lead">
A small application packet for one future lover: equal parts job description, personal CV, and
honest invitation to build something kind.
</p>
<div class="button-row">
<a class="button" href={resolve('/jd/')}>Read the JD</a>
<a class="button secondary" href={resolve('/cv/')}>Review the CV</a>
</div>
</div>
</section>
<section class="site-shell page-section section-grid" aria-labelledby="packet-title">
<div>
<p class="eyebrow">Application packet</p>
<h2 id="packet-title">A serious joke, lightly managed.</h2>
</div>
<div class="panel-list">
<article class="panel strong">
<h3>For the future lover</h3>
<p>
The JD explains what this role receives: steadiness, attention, humor, emotional
maintenance, and a partner who treats care as daily work, not launch-day theater.
</p>
</article>
<article class="panel">
<h3>For the hiring committee</h3>
<p>
The CV summarizes the applicant: software engineer, systems thinker, patient debugger, and
human still actively refactoring bad habits.
</p>
</article>
</div>
</section>
<style>
.home-hero {
min-height: min(760px, 82dvh);
display: flex;
align-items: center;
margin-top: -5rem;
padding-top: 6rem;
background-position: center;
background-size: cover;
color: white;
}
.hero-copy {
padding-block: clamp(5rem, 12vw, 8rem);
}
.hero-copy .lead {
margin-top: 1.5rem;
color: rgba(255, 255, 255, 0.86);
}
.hero-copy .eyebrow {
color: #f3c36f;
}
.hero-copy .button.secondary {
border-color: rgba(255, 255, 255, 0.72);
color: white;
}
</style>
+101
View File
@@ -0,0 +1,101 @@
<script lang="ts">
import { cvFacts, cvStrengths } from '$lib/site-content';
</script>
<svelte:head>
<title>CV | Tien Nguyen Minh</title>
<meta
name="description"
content="A warm personal CV for Tien Nguyen Minh, rewritten for a future lover."
/>
</svelte:head>
<section class="site-shell page-section cv-hero">
<p class="eyebrow">Candidate CV</p>
<h1>Tien Nguyen Minh</h1>
<p class="lead">
Senior Software Engineer, backend systems builder, game-server caretaker, and candidate for one
emotionally responsible long-term partnership.
</p>
<div class="meta-grid" aria-label="Candidate summary">
{#each cvFacts.slice(0, 3) as fact (fact[0])}
<div><span>{fact[0]}</span>{fact[1]}</div>
{/each}
</div>
</section>
<section class="site-shell page-section section-grid" aria-labelledby="strengths-title">
<div>
<p class="eyebrow">Core strengths</p>
<h2 id="strengths-title">Why shortlist this candidate.</h2>
</div>
<div class="panel-list">
{#each cvStrengths as strength (strength.title)}
<article class="panel">
<h3>{strength.title}</h3>
<p>{strength.body}</p>
</article>
{/each}
</div>
</section>
<section class="site-shell page-section section-grid" aria-labelledby="facts-title">
<div>
<p class="eyebrow">Reference sheet</p>
<h2 id="facts-title">Useful facts.</h2>
</div>
<div class="facts-list">
{#each cvFacts as fact (fact[0])}
<div>
<span>{fact[0]}</span>
<strong>{fact[1]}</strong>
</div>
{/each}
</div>
</section>
<section class="site-shell page-section section-grid" aria-labelledby="closing-title">
<div>
<p class="eyebrow">Closing statement</p>
<h2 id="closing-title">The honest version.</h2>
</div>
<article class="panel strong">
<p>
I am not a perfect product. I am a maintained system: observable, sometimes stubborn,
generally reliable, and much better with the right person reviewing the roadmap.
</p>
</article>
</section>
<style>
.cv-hero {
padding-top: clamp(4rem, 10vw, 8rem);
}
.facts-list {
display: grid;
gap: 1px;
background: var(--line);
}
.facts-list div {
display: grid;
grid-template-columns: minmax(9rem, 0.7fr) 1fr;
gap: 1rem;
background: rgba(247, 244, 237, 0.86);
padding: 1rem;
}
.facts-list span {
color: var(--blueprint);
font-size: 0.8rem;
font-weight: 700;
text-transform: uppercase;
}
@media (max-width: 620px) {
.facts-list div {
grid-template-columns: 1fr;
}
}
</style>
+84
View File
@@ -0,0 +1,84 @@
<script lang="ts">
import { niceToHave, roleBenefits, roleResponsibilities } from '$lib/site-content';
</script>
<svelte:head>
<title>JD | Future Lover Role</title>
<meta
name="description"
content="Rights, benefits, responsibilities, and selection notes for the future lover role."
/>
</svelte:head>
<section class="site-shell page-section jd-hero">
<p class="eyebrow">Job description</p>
<h1>Future Lover</h1>
<p class="lead">
This is a long-term, human-facing role. The compensation package is mostly attention, loyalty,
shared meals, private jokes, and someone who will try again after mistakes.
</p>
<div class="meta-grid" aria-label="Role summary">
<div><span>Type</span>Full-time heart, flexible schedule</div>
<div><span>Location</span>Mostly Earth, sometimes HCMC</div>
<div><span>Start date</span>When trust passes review</div>
</div>
</section>
<section class="site-shell page-section section-grid" aria-labelledby="benefits-title">
<div>
<p class="eyebrow">Rights & benefits</p>
<h2 id="benefits-title">What you receive.</h2>
</div>
<div class="panel-list">
{#each roleBenefits as benefit (benefit)}
<article class="panel">
<p>{benefit}</p>
</article>
{/each}
</div>
</section>
<section class="site-shell page-section section-grid" aria-labelledby="responsibilities-title">
<div>
<p class="eyebrow">Responsibilities</p>
<h2 id="responsibilities-title">What we both protect.</h2>
</div>
<div class="panel-list">
<article class="panel strong">
<ul>
{#each roleResponsibilities as responsibility (responsibility)}
<li>{responsibility}</li>
{/each}
</ul>
</article>
</div>
</section>
<section class="site-shell page-section section-grid" aria-labelledby="process-title">
<div>
<p class="eyebrow">Nice to have</p>
<h2 id="process-title">Interview process.</h2>
</div>
<div class="panel-list">
<article class="panel">
<ul>
{#each niceToHave as item (item)}
<li>{item}</li>
{/each}
</ul>
</article>
<article class="panel">
<h3>Selection notes</h3>
<p>
No pressure test. No hidden puzzle round. Strong candidates are kind when tired, direct when
confused, and willing to choose each other in small boring moments.
</p>
</article>
</div>
</section>
<style>
.jd-hero {
padding-top: clamp(4rem, 10vw, 8rem);
}
</style>
+3
View File
@@ -0,0 +1,3 @@
# allow crawling everything by default
User-agent: *
Disallow:
+20
View File
@@ -0,0 +1,20 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"rewriteRelativeImportExtensions": true,
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// To make changes to top-level options such as include and exclude, we recommend extending
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
}
+34
View File
@@ -0,0 +1,34 @@
import adapter from '@sveltejs/adapter-static';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
function resolveBase(): '' | `/${string}` {
const configuredBase =
process.env.BASE_PATH ?? (process.env.BUILD_PROFILE === 'gh' ? '/dating' : '');
if (configuredBase === '' || configuredBase.startsWith('/')) {
return configuredBase as '' | `/${string}`;
}
throw new Error('BASE_PATH must be empty or start with "/"');
}
export default defineConfig({
plugins: [
sveltekit({
compilerOptions: {
// Force runes mode for the project, except for libraries. Can be removed in svelte 6.
runes: ({ filename }) =>
filename.split(/[/\\]/).includes('node_modules') ? undefined : true
},
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: '404.html',
strict: true
}),
paths: { base: resolveBase() }
})
]
});