Skip to content

Commit 9105bf5

Browse files
committed
feat!: view transitions; better navigation
1 parent e44cd34 commit 9105bf5

21 files changed

Lines changed: 197 additions & 81 deletions

src/features/matrix-rain/matrix-rain/matrixRain.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export class MatrixRain {
8787
init = () => {
8888
this.resize();
8989

90-
this.canvas.addEventListener("resize", this.resize);
90+
window.addEventListener("resize", this.resize);
9191
window.addEventListener("mousemove", this.mousemove);
9292
};
9393

@@ -96,7 +96,7 @@ export class MatrixRain {
9696
cancelAnimationFrame(this.animationId);
9797
}
9898

99-
this.canvas.removeEventListener("resize", this.resize);
99+
window.removeEventListener("resize", this.resize);
100100
window.removeEventListener("mousemove", this.mousemove);
101101
};
102102
}

src/features/music/components/MusicPlayer.svelte

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
<script lang="ts">
2-
import { Info, Music, Pause, Play, StepForward } from "@lucide/svelte";
2+
import {
3+
Forward,
4+
Info,
5+
Music,
6+
Pause,
7+
Play,
8+
StepForward,
9+
} from "@lucide/svelte";
10+
import { afterNavigate } from "$app/navigation";
311
import { CONTROLS_DELAY } from "$lib/config";
412
import { mp } from "$lib/stores/mp.svelte";
513
import { ON_MOBILE } from "$lib/utils/common";
@@ -13,9 +21,15 @@
1321
let showControls = $state(false);
1422
let showToast = $state(false);
1523
16-
$effect(() => {
24+
afterNavigate(({ from }) => {
1725
mp.audioEl = audioEl;
1826
27+
if (from?.url) {
28+
modalEl?.showModal();
29+
showControls = true;
30+
return;
31+
}
32+
1933
setTimeout(() => {
2034
modalEl?.showModal();
2135
showControls = true;
@@ -90,8 +104,8 @@
90104
<div class="font-oxanium">
91105
<p class="pt-2">Turn up the volume;</p>
92106
<p>Hit notes to score!</p>
93-
<div class="flex items-center gap-2 py-2">
94-
{#if ON_MOBILE}
107+
{#if ON_MOBILE}
108+
<div class="flex items-center gap-2 py-2">
95109
Use
96110
<div class="flex items-center gap-1">
97111
<kbd class="kbd">◀︎</kbd>
@@ -102,10 +116,10 @@
102116
<kbd class="kbd">▶︎</kbd>
103117
</div>
104118
or your mouse;
105-
{:else}
106-
Tap the sides of your screen;
107-
{/if}
108-
</div>
119+
</div>
120+
{:else}
121+
<p>Tap the sides of your screen;</p>
122+
{/if}
109123
<p>Scroll down to learn more!</p>
110124
</div>
111125
<div class="modal-action">
@@ -119,13 +133,13 @@
119133

120134
{#if showControls}
121135
<div class="fixed bottom-4 flex w-screen justify-center gap-4">
122-
<div class="tooltip tooltip-top" data-tip="Track info">
136+
<div class="tooltip tooltip-left" data-tip="Track info">
123137
<button class="btn px-2 btn-soft btn-primary" onclick={toast}>
124138
<Info />
125139
</button>
126140
</div>
127141
<div
128-
class="tooltip tooltip-top"
142+
class="tooltip tooltip-left"
129143
data-tip={mp.paused ? "Play" : "Pause"}
130144
>
131145
<button
@@ -135,13 +149,20 @@
135149
{#if mp.paused}<Play />{:else}<Pause />{/if}
136150
</button>
137151
</div>
138-
<div class="tooltip tooltip-top" data-tip="Skip track">
152+
<div class="tooltip tooltip-left" data-tip="Skip track">
139153
<button class="btn px-2 btn-soft btn-primary" onclick={play}>
140154
<StepForward />
141155
</button>
142156
</div>
143157
</div>
144158

159+
<!-- <div class="fixed top-8 right-4"> -->
160+
<!-- <a class="btn animate-bounce btn-outline btn-secondary" href="/bio"> -->
161+
<!-- <Forward /> -->
162+
<!-- Go to Bio! -->
163+
<!-- </a> -->
164+
<!-- </div> -->
165+
145166
{#if showToast}
146167
<div class="toast z-50">
147168
<div class="alert alert-info">

src/features/navbar/components/Navbar.svelte

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
import { Github } from "@lucide/svelte";
33
</script>
44

5-
<nav class="flex h-16 items-center bg-base-300 px-4">
5+
<nav id="navbar" class="flex h-16 items-center bg-base-300 px-4">
66
<a class="font-rocket-rinder text-xl text-secondary" href="/">
77
Neal Wang
88
</a>
99
<div class="absolute left-1/2 -translate-x-1/2 font-cascadia-code">
10-
<a class="link link-secondary link-hover" href="/">main</a>
10+
<a class="link link-secondary link-hover" href="/bio">main</a>
1111
<span> :: </span>
1212
<a class="link link-secondary link-hover" href="/experience">
1313
Experience
@@ -24,12 +24,18 @@
2424
</a>
2525
<span> -> </span>
2626
<a class="link link-secondary link-hover" href="/uses">Uses</a>
27-
<span> -> </span>
28-
<a class="link link-secondary link-hover" href="/contact">IO</a>
2927
<span class="text-primary">()</span>
3028
</div>
3129
<div class="flex-1"></div>
32-
<a href="https://github.com/neowsl/neowsl.github.io" target="_blank">
33-
<Github />
34-
</a>
30+
<div class="tooltip tooltip-left" data-tip="GitHub repo">
31+
<a href="https://github.com/neowsl/neowsl.github.io" target="_blank">
32+
<Github />
33+
</a>
34+
</div>
3535
</nav>
36+
37+
<style>
38+
#navbar {
39+
view-transition-name: navbar;
40+
}
41+
</style>

src/lib/utils/common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export const ON_MOBILE =
22
typeof window !== "undefined"
3-
? window.matchMedia("(max-width: 768px)").matches
3+
? !window.matchMedia("(max-width: 768px)").matches
44
: false;

src/routes/+layout.svelte

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
<script lang="ts">
22
import "../app.css";
3+
import { onNavigate } from "$app/navigation";
34
import { page } from "$app/state";
45
import InceptionTop from "$features/inception-top/components/InceptionTop.svelte";
56
import Navbar from "$features/navbar/components/Navbar.svelte";
6-
import favicon from "$lib/assets/favicon.svg";
77
88
let { children } = $props();
99
1010
const main = $derived(page.url.pathname === "/");
11+
12+
onNavigate((navigation) => {
13+
if (!document.startViewTransition) {
14+
return;
15+
}
16+
17+
return new Promise((resolve) => {
18+
document.startViewTransition(async () => {
19+
resolve();
20+
await navigation.complete;
21+
});
22+
});
23+
});
1124
</script>
1225

1326
<svelte:head>
14-
<link rel="icon" href={favicon} />
27+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
28+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
29+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
30+
<link rel="manifest" href="/site.webmanifest" />
31+
32+
<title>Neal Wang</title>
1533

1634
<link rel="preconnect" href="https://fonts.googleapis.com" />
1735
<link
@@ -50,6 +68,7 @@
5068
</div>
5169

5270
<footer
71+
id="footer"
5372
class="footer-center footer p-4 text-base-content sm:footer-horizontal"
5473
>
5574
<aside>
@@ -61,3 +80,9 @@
6180
</footer>
6281
</div>
6382
{/if}
83+
84+
<style>
85+
#footer {
86+
view-transition-name: footer;
87+
}
88+
</style>

src/routes/+page.svelte

Lines changed: 39 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
22
import { Canvas } from "@threlte/core";
3+
import { afterNavigate } from "$app/navigation";
34
import MatrixRain from "$features/matrix-rain/components/MatrixRain.svelte";
45
import MusicPlayer from "$features/music/components/MusicPlayer.svelte";
56
import Score from "$features/synthwave/components/Score.svelte";
@@ -8,14 +9,22 @@
89
import MetallicText from "$lib/components/MetallicText.svelte";
910
import { CONTROLS_DELAY } from "$lib/config";
1011
import gsap from "gsap";
11-
import { onMount } from "svelte";
1212
13+
let showVisuals: boolean | null = $state(null);
1314
let heroEl: HTMLElement | null = $state(null);
14-
let scoreVisible: boolean | null = $state(null);
15-
let matrixRainVisible: boolean | null = $state(null);
1615
let synthwaveVisible = $state(true);
16+
let externalNavigation = $state(false);
17+
18+
afterNavigate(({ from }) => {
19+
if (from?.url) {
20+
if (showVisuals === null) {
21+
showVisuals = true;
22+
}
23+
return;
24+
}
25+
26+
externalNavigation = true;
1727
18-
$effect(() => {
1928
const tl = gsap.timeline();
2029
tl.from("#title", { opacity: 0, duration: 1, ease: "power1.out" });
2130
tl.delay(1);
@@ -26,64 +35,22 @@
2635
duration: 3,
2736
ease: "power1.out",
2837
});
29-
});
3038
31-
$effect(() => {
3239
setTimeout(() => {
33-
if (scoreVisible === null) {
34-
scoreVisible = true;
35-
}
36-
if (matrixRainVisible === null) {
37-
matrixRainVisible = true;
40+
if (showVisuals === null) {
41+
showVisuals = true;
3842
}
3943
}, CONTROLS_DELAY);
4044
});
41-
42-
onMount(() => {
43-
const scoreObserver = new IntersectionObserver(
44-
([entry]) => {
45-
if (scoreVisible !== null) {
46-
scoreVisible = entry.isIntersecting;
47-
}
48-
},
49-
{ threshold: 0.9 },
50-
);
51-
const matrixRainObserver = new IntersectionObserver(
52-
([entry]) => {
53-
if (matrixRainVisible !== null) {
54-
matrixRainVisible = entry.isIntersecting;
55-
}
56-
},
57-
{ threshold: 0.1 },
58-
);
59-
const synthwaveObserver = new IntersectionObserver(
60-
([entry]) => {
61-
synthwaveVisible = entry.isIntersecting;
62-
},
63-
{ threshold: 0.1 },
64-
);
65-
66-
if (heroEl) {
67-
matrixRainObserver.observe(heroEl);
68-
synthwaveObserver.observe(heroEl);
69-
scoreObserver.observe(heroEl);
70-
}
71-
72-
return () => {
73-
matrixRainObserver.disconnect();
74-
synthwaveObserver.disconnect();
75-
scoreObserver.disconnect();
76-
};
77-
});
7845
</script>
7946

8047
<MusicPlayer />
8148

82-
{#if scoreVisible}
49+
{#if showVisuals}
8350
<Score />
8451
{/if}
8552

86-
{#if matrixRainVisible}
53+
{#if showVisuals}
8754
<div class="fixed z-[-30] h-[75vh] w-screen">
8855
<MatrixRain />
8956
</div>
@@ -99,22 +66,28 @@
9966
</div>
10067
{/if}
10168

102-
<div class="flex h-screen flex-col items-center" bind:this={heroEl}>
69+
<div id="hero" class="flex h-screen flex-col items-center" bind:this={heroEl}>
10370
<div id="title" class="mt-[20vh] flex flex-col items-center">
104-
<h1 class="mb-[-0.4em] text-5xl sm:text-7xl md:text-8xl">
105-
<MetallicText>Neal Wang</MetallicText>
106-
</h1>
71+
<div
72+
class={`tooltip ${externalNavigation && showVisuals ? "tooltip-open" : ""}`}
73+
data-tip="Click me!"
74+
>
75+
<a class="cursor-pointer" href="/bio">
76+
<h1
77+
id="name"
78+
class="mb-[-0.4em] text-5xl sm:text-7xl md:text-8xl"
79+
>
80+
<MetallicText>Neal Wang</MetallicText>
81+
</h1>
82+
</a>
83+
</div>
10784
<div id="glitch">
10885
<Glitch />
10986
</div>
11087
</div>
11188
</div>
11289

11390
<style>
114-
* {
115-
@apply cursor-none;
116-
}
117-
11891
#synthwave-background {
11992
background: linear-gradient(
12093
to bottom,
@@ -123,4 +96,12 @@
12396
oklch(15% 0.09 281.288)
12497
);
12598
}
99+
100+
#hero {
101+
@apply cursor-none;
102+
}
103+
104+
#name {
105+
view-transition-name: name;
106+
}
126107
</style>

0 commit comments

Comments
 (0)