Skip to content

Commit 2c50872

Browse files
committed
Send sidebar position in cookie to avoid layout shift with SSR
1 parent 970d89d commit 2c50872

File tree

4 files changed

+29
-9
lines changed

4 files changed

+29
-9
lines changed

web/src/lib/diff-viewer-multi-file.svelte.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,19 @@ import { MediaQuery } from "svelte/reactivity";
2929
export type SidebarLocation = "left" | "right";
3030

3131
export class GlobalOptions {
32-
private static readonly localStorageKey = "diff-viewer-global-options";
33-
private static readonly context = new Context<GlobalOptions>(GlobalOptions.localStorageKey);
32+
static readonly key = "diff-viewer-global-options";
33+
private static readonly context = new Context<GlobalOptions>(GlobalOptions.key);
3434

35-
static init() {
35+
static init(cookie?: string) {
3636
const opts = new GlobalOptions();
3737
if (!browser) {
3838
GlobalOptions.context.set(opts);
39+
if (cookie) {
40+
opts.deserialize(cookie);
41+
}
3942
return opts;
4043
}
41-
const serialized = localStorage.getItem(GlobalOptions.localStorageKey);
44+
const serialized = localStorage.getItem(GlobalOptions.key);
4245
if (serialized !== null) {
4346
opts.deserialize(serialized);
4447
}
@@ -56,15 +59,14 @@ export class GlobalOptions {
5659
wordDiffs = $state(true);
5760
lineWrap = $state(true);
5861
omitPatchHeaderOnlyHunks = $state(true);
59-
// TODO: send to server (use cookie?) to that the initial position is correct
6062
sidebarLocation: SidebarLocation = $state("left");
6163

6264
private constructor() {
6365
$effect(() => {
6466
this.save();
6567
});
6668

67-
watchLocalStorage(GlobalOptions.localStorageKey, (newValue) => {
69+
watchLocalStorage(GlobalOptions.key, (newValue) => {
6870
if (newValue) {
6971
this.deserialize(newValue);
7072
}
@@ -84,7 +86,8 @@ export class GlobalOptions {
8486
if (!browser) {
8587
return;
8688
}
87-
localStorage.setItem(GlobalOptions.localStorageKey, this.serialize());
89+
localStorage.setItem(GlobalOptions.key, this.serialize());
90+
document.cookie = `${GlobalOptions.key}=${encodeURIComponent(this.serializeCookie())}; path=/; max-age=31536000; SameSite=Lax`;
8891
}
8992

9093
private serialize() {
@@ -105,6 +108,14 @@ export class GlobalOptions {
105108
return JSON.stringify(cereal);
106109
}
107110

111+
private serializeCookie() {
112+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
113+
const cereal: any = {
114+
sidebarLocation: this.sidebarLocation,
115+
};
116+
return JSON.stringify(cereal);
117+
}
118+
108119
private deserialize(serialized: string) {
109120
const jsonObject = JSON.parse(serialized);
110121
if (jsonObject.syntaxHighlighting !== undefined) {

web/src/routes/+layout.server.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { LayoutServerLoad } from "./$types";
2+
import { GlobalOptions } from "$lib/diff-viewer-multi-file.svelte";
3+
4+
export const load: LayoutServerLoad = async ({ cookies }) => {
5+
return {
6+
globalOptions: cookies.get(GlobalOptions.key),
7+
};
8+
};

web/src/routes/+layout.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

web/src/routes/+page.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232
import { Button, Label } from "bits-ui";
3333
import { onClickOutside } from "runed";
3434
import SidebarToggle from "./SidebarToggle.svelte";
35+
import type { PageProps } from "./$types";
3536
36-
const globalOptions = GlobalOptions.init();
37+
let { data }: PageProps = $props();
38+
const globalOptions = GlobalOptions.init(data.globalOptions);
3739
const viewer = MultiFileDiffViewerState.init();
3840
let sidebarElement: HTMLDivElement | undefined = $state();
3941

0 commit comments

Comments
 (0)