aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/components/AppTitle.svelte41
-rw-r--r--lib/components/AppVersion.svelte20
-rw-r--r--lib/components/BeginActions.svelte50
-rw-r--r--lib/components/BeginScreen.svelte48
-rw-r--r--lib/components/InitialLoadScreen.svelte56
-rw-r--r--lib/components/MenuButton.svelte51
-rw-r--r--lib/components/ProgressBar.svelte34
-rw-r--r--lib/version.ts12
8 files changed, 312 insertions, 0 deletions
diff --git a/lib/components/AppTitle.svelte b/lib/components/AppTitle.svelte
new file mode 100644
index 0000000..ce5c859
--- /dev/null
+++ b/lib/components/AppTitle.svelte
@@ -0,0 +1,41 @@
+<script lang="ts">
+ interface Props {
+ size?: number
+ subtitle?: string | null
+ letterSpacing?: number
+ }
+
+ let { size = 38, subtitle = null, letterSpacing = 2 }: Props = $props()
+</script>
+
+<div class="app-title">
+ <p class="name" style:font-size="{size}px" style:letter-spacing="{letterSpacing}px">
+ Hollowdark
+ </p>
+ {#if subtitle}
+ <p class="subtitle">{subtitle}</p>
+ {/if}
+</div>
+
+<style>
+ .app-title {
+ text-align: center;
+ }
+
+ .name {
+ font-family: var(--font-body);
+ font-style: italic;
+ font-weight: 400;
+ color: var(--color-text);
+ margin: 0 0 var(--space-6);
+ }
+
+ .subtitle {
+ font-family: var(--font-ui);
+ font-size: 11px;
+ color: var(--color-text-tertiary);
+ letter-spacing: 2px;
+ text-transform: uppercase;
+ margin: 0;
+ }
+</style>
diff --git a/lib/components/AppVersion.svelte b/lib/components/AppVersion.svelte
new file mode 100644
index 0000000..315a47b
--- /dev/null
+++ b/lib/components/AppVersion.svelte
@@ -0,0 +1,20 @@
+<script lang="ts">
+ import { APP_VERSION } from '@hollowdark/lib/version'
+</script>
+
+<p class="app-version">v {APP_VERSION}</p>
+
+<style>
+ .app-version {
+ position: absolute;
+ bottom: var(--space-6);
+ left: 0;
+ right: 0;
+ margin: 0;
+ text-align: center;
+ font-family: var(--font-ui);
+ font-size: 10px;
+ color: #3d382f;
+ letter-spacing: 1px;
+ }
+</style>
diff --git a/lib/components/BeginActions.svelte b/lib/components/BeginActions.svelte
new file mode 100644
index 0000000..3ed96c4
--- /dev/null
+++ b/lib/components/BeginActions.svelte
@@ -0,0 +1,50 @@
+<script lang="ts">
+ import MenuButton from '@hollowdark/lib/components/MenuButton.svelte'
+ import type { BeginState } from '@hollowdark/loading/session'
+
+ interface Props {
+ state: BeginState
+ onBegin: () => void
+ onContinue?: () => void
+ onSettings: () => void
+ onCredits: () => void
+ }
+
+ let {
+ state,
+ onBegin,
+ onContinue,
+ onSettings,
+ onCredits
+ }: Props = $props()
+
+ function handleContinue(): void {
+ onContinue?.()
+ }
+</script>
+
+<div class="begin-actions">
+ {#if state.kind === 'first-ever'}
+ <MenuButton variant="primary" onclick={onBegin}>Begin</MenuButton>
+ {:else if state.kind === 'returning-active'}
+ <MenuButton variant="primary" onclick={handleContinue}>
+ Continue {state.characterName}'s life
+ </MenuButton>
+ <MenuButton variant="secondary" onclick={onBegin}>Begin a new life</MenuButton>
+ {:else}
+ <MenuButton variant="primary" onclick={handleContinue}>Continue</MenuButton>
+ <MenuButton variant="secondary" onclick={onBegin}>Begin a new life</MenuButton>
+ {/if}
+
+ <MenuButton variant="tertiary" onclick={onSettings}>Settings</MenuButton>
+ <MenuButton variant="tertiary" onclick={onCredits}>Credits</MenuButton>
+</div>
+
+<style>
+ .begin-actions {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--space-8);
+ }
+</style>
diff --git a/lib/components/BeginScreen.svelte b/lib/components/BeginScreen.svelte
new file mode 100644
index 0000000..5832a42
--- /dev/null
+++ b/lib/components/BeginScreen.svelte
@@ -0,0 +1,48 @@
+<script lang="ts">
+ import AppTitle from '@hollowdark/lib/components/AppTitle.svelte'
+ import AppVersion from '@hollowdark/lib/components/AppVersion.svelte'
+ import BeginActions from '@hollowdark/lib/components/BeginActions.svelte'
+ import type { BeginState } from '@hollowdark/loading/session'
+
+ interface Props {
+ state: BeginState
+ onBegin: () => void
+ onContinue?: () => void
+ onSettings: () => void
+ onCredits: () => void
+ }
+
+ let {
+ state,
+ onBegin,
+ onContinue,
+ onSettings,
+ onCredits
+ }: Props = $props()
+</script>
+
+<section class="begin">
+ <div class="top">
+ <AppTitle size={38} subtitle="A Literary Life Simulation" />
+ </div>
+
+ <BeginActions {state} {onBegin} {onContinue} {onSettings} {onCredits} />
+
+ <AppVersion />
+</section>
+
+<style>
+ .begin {
+ min-height: 100dvh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--space-12);
+ position: relative;
+ }
+
+ .top {
+ margin-bottom: 120px;
+ }
+</style>
diff --git a/lib/components/InitialLoadScreen.svelte b/lib/components/InitialLoadScreen.svelte
new file mode 100644
index 0000000..3800715
--- /dev/null
+++ b/lib/components/InitialLoadScreen.svelte
@@ -0,0 +1,56 @@
+<script lang="ts">
+ import AppTitle from '@hollowdark/lib/components/AppTitle.svelte'
+ import ProgressBar from '@hollowdark/lib/components/ProgressBar.svelte'
+ import { loadingProgress } from '@hollowdark/loading/progress'
+
+ const progress = $derived($loadingProgress)
+</script>
+
+<section class="initial-load">
+ <div class="top">
+ <AppTitle size={32} letterSpacing={1} />
+ </div>
+
+ <div class="bar">
+ <ProgressBar value={progress.percentage} />
+ </div>
+
+ <p class="message">{progress.currentMessage}</p>
+ <p class="note">This will happen once. It will not happen again.</p>
+</section>
+
+<style>
+ .initial-load {
+ min-height: 100dvh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--space-12);
+ text-align: center;
+ }
+
+ .top {
+ margin-bottom: 120px;
+ }
+
+ .bar {
+ margin-bottom: var(--space-6);
+ }
+
+ .message {
+ font-family: var(--font-ui);
+ font-size: 12px;
+ color: var(--color-text-secondary);
+ letter-spacing: 0.5px;
+ margin: 0 0 var(--space-2);
+ }
+
+ .note {
+ font-family: var(--font-ui);
+ font-size: 11px;
+ color: var(--color-text-tertiary);
+ letter-spacing: 0.3px;
+ margin: 0;
+ }
+</style>
diff --git a/lib/components/MenuButton.svelte b/lib/components/MenuButton.svelte
new file mode 100644
index 0000000..1753155
--- /dev/null
+++ b/lib/components/MenuButton.svelte
@@ -0,0 +1,51 @@
+<script lang="ts">
+ type Variant = 'primary' | 'secondary' | 'tertiary'
+
+ interface Props {
+ variant?: Variant
+ onclick: () => void
+ children: import('svelte').Snippet
+ }
+
+ let { variant = 'primary', onclick, children }: Props = $props()
+</script>
+
+<button class="menu-button {variant}" {onclick}>
+ {@render children()}
+</button>
+
+<style>
+ .menu-button {
+ font-family: var(--font-body);
+ letter-spacing: 0.3px;
+ transition: color var(--transition-fast);
+ }
+
+ .primary {
+ font-size: var(--text-lg);
+ color: var(--color-accent);
+ letter-spacing: 0.5px;
+ }
+
+ .primary:hover {
+ color: var(--color-text);
+ }
+
+ .secondary {
+ font-size: 15px;
+ color: var(--color-text-secondary);
+ }
+
+ .secondary:hover {
+ color: var(--color-text);
+ }
+
+ .tertiary {
+ font-size: 13px;
+ color: var(--color-text-tertiary);
+ }
+
+ .tertiary:hover {
+ color: var(--color-text-secondary);
+ }
+</style>
diff --git a/lib/components/ProgressBar.svelte b/lib/components/ProgressBar.svelte
new file mode 100644
index 0000000..21c9e68
--- /dev/null
+++ b/lib/components/ProgressBar.svelte
@@ -0,0 +1,34 @@
+<script lang="ts">
+ interface Props {
+ value: number
+ width?: number
+ }
+
+ let { value, width = 320 }: Props = $props()
+
+ const percentage = $derived(Math.max(0, Math.min(1, value)) * 100)
+</script>
+
+<div class="progress-track" style:width="{width}px">
+ <div class="progress-fill" style:width="{percentage}%"></div>
+</div>
+
+<style>
+ .progress-track {
+ height: 2px;
+ background: rgba(232, 226, 213, 0.06);
+ border-radius: 1px;
+ position: relative;
+ overflow: hidden;
+ }
+
+ .progress-fill {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ background: var(--color-accent);
+ border-radius: 1px;
+ transition: width 300ms ease-out;
+ }
+</style>
diff --git a/lib/version.ts b/lib/version.ts
new file mode 100644
index 0000000..e8322e3
--- /dev/null
+++ b/lib/version.ts
@@ -0,0 +1,12 @@
+import pkg from '@hollowdark/package.json'
+
+const [major, minor] = pkg.version.split('.')
+
+/**
+ * The app's version in short display form (`<major>.<minor>`), derived from
+ * the `version` field in `package.json`. Displayed in the UI footer.
+ */
+export const APP_VERSION: string = `${major}.${minor}`
+
+/** The full semver string from `package.json`. */
+export const APP_VERSION_FULL: string = pkg.version