Skip to content

Commit

Permalink
feat: menu collapse global css (#278)
Browse files Browse the repository at this point in the history
# Motivation

Prefer usage of global CSS instead of JS to define the "collapsed" state
of the menu, this to avoid glitch when deployed on mainnet.
  • Loading branch information
peterpeterparker authored Aug 21, 2023
1 parent e5a968e commit 969b784
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 73 deletions.
18 changes: 18 additions & 0 deletions src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,24 @@
}
</script>

<!-- Init menu as fast as possible as well -->
<script>
try {
const currentMenu = ["collapsed", "expanded"].includes(
localStorage.nnsMenu,
)
? JSON.parse(localStorage.nnsMenu)
: undefined;

document.documentElement.setAttribute(
"menu",
currentMenu ?? "expanded",
);
} catch (error) {
console.error("Error initializing menu", error);
}
</script>

%sveltekit.head%
</head>
<body>
Expand Down
59 changes: 10 additions & 49 deletions src/lib/components/Menu.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
<script lang="ts">
import MenuBackground from "./MenuBackground.svelte";
import {
layoutMenuCollapsed,
layoutMenuOpen,
} from "$lib/stores/layout.store";
import { layoutMenuOpen } from "$lib/stores/layout.store";
import { handleKeyPress } from "$lib/utils/keyboard.utils";
import IconEast from "$lib/icons/IconEast.svelte";
import { applyMenu } from "$lib/utils/menu.utils";
import { Menu } from "$lib/types/menu";
export let sticky = true;
const close = () => layoutMenuOpen.set(false);
</script>

<div role="menu" class:collapsed={!$layoutMenuOpen && $layoutMenuCollapsed}>
<div role="menu" class:open={$layoutMenuOpen}>
<MenuBackground />

<div
Expand All @@ -27,17 +26,15 @@
>
<slot />

<div class="expand">
<button on:click={() => layoutMenuCollapsed.set(false)} class:visible={$layoutMenuCollapsed}
><IconEast /></button
>
</div>
<button
class="menu-expand"
on:click={() => applyMenu({ menu: Menu.EXPANDED })}><IconEast /></button
>
</div>

<button
class="bottom"
on:click={() => layoutMenuCollapsed.set(true)}
class:visible={!$layoutMenuCollapsed}><IconEast /></button
class="menu-collapse"
on:click={() => applyMenu({ menu: Menu.COLLAPSED })}><IconEast /></button
>
</div>

Expand Down Expand Up @@ -67,16 +64,6 @@
}
position: relative;
--menu-width: var(--menu-expanded-width);
&.collapsed {
--menu-width: var(--menu-collapsed-width);
.inner {
overflow-x: hidden;
}
}
}
.inner {
Expand Down Expand Up @@ -116,30 +103,4 @@
padding-top: var(--padding-4x);
}
}
.bottom {
position: absolute;
right: 0;
bottom: 64px;
transform: rotate(-180deg);
}
button {
opacity: 0;
visibility: hidden;
transition: opacity var(--animation-time-long);
padding: var(--padding-1_5x);
@include media.min-width(large) {
&.visible {
opacity: 1;
visibility: visible;
}
}
}
.expand {
display: flex;
}
</style>
9 changes: 2 additions & 7 deletions src/lib/components/MenuBackground.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import backgroundLight from "$lib/assets/menu-bg-light.png";
import { themeStore } from "$lib/stores/theme.store";
import { Theme } from "$lib/types/theme";
import {layoutMenuCollapsed, layoutMenuOpen} from "$lib/stores/layout.store";
import { layoutMenuOpen } from "$lib/stores/layout.store";
import { nonNullish } from "@dfinity/utils";
let logoOnChain: string;
Expand All @@ -18,7 +18,7 @@
$themeStore === Theme.LIGHT ? backgroundLight : backgroundDark;
</script>

<div class:open={$layoutMenuOpen} class:collapsed={$layoutMenuCollapsed}>
<div class:open={$layoutMenuOpen} class="menu-background">
<img
class="logo-nns"
src={logoNNS}
Expand Down Expand Up @@ -104,9 +104,4 @@
bottom: 0;
left: 0;
}
.collapsed {
visibility: hidden;
opacity: 0;
}
</style>
16 changes: 0 additions & 16 deletions src/lib/components/MenuItem.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<script lang="ts">
import {layoutMenuCollapsed, layoutMenuOpen} from "$lib/stores/layout.store";
export let href: string;
export let selected = false;
export let testId: string | undefined = undefined;
Expand All @@ -14,7 +12,6 @@
{rel}
{target}
class:selected
class:icon-only={!$layoutMenuOpen && $layoutMenuCollapsed}
data-tid={testId}
on:click
>
Expand Down Expand Up @@ -82,17 +79,4 @@
margin: 0 var(--padding) 0 var(--padding-2x);
}
span, div {
opacity: 1;
visibility: visible;
transition: opacity var(--animation-time-normal);
}
.icon-only {
span, div {
opacity: 0;
visibility: hidden;
}
}
</style>
1 change: 0 additions & 1 deletion src/lib/stores/layout.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ import { writable } from "svelte/store";

export const layoutBottomOffset = writable<number>(0);
export const layoutMenuOpen = writable<boolean>(false);
export const layoutMenuCollapsed = writable<boolean>(false);
export const layoutContentScrollY = writable<"hidden" | "auto">("auto");
20 changes: 20 additions & 0 deletions src/lib/stores/menu.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Menu } from "$lib/types/menu";
import { applyMenu, initMenu } from "$lib/utils/menu.utils";
import { writable } from "svelte/store";

const initialMenu: Menu | undefined = initMenu();

export const initMenuStore = () => {
const { subscribe, set } = writable<Menu | undefined>(initialMenu);

return {
subscribe,

select: (menu: Menu) => {
applyMenu({ menu, preserve: true });
set(menu);
},
};
};

export const menuStore = initMenuStore();
1 change: 1 addition & 0 deletions src/lib/styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@import "./global/utility-classes.scss";
@import "./global/blockquote.scss";
@import "./global/scrollbar.scss";
@import "./global/menu.scss";

@import "./themes/dark.scss";
@import "./themes/light.scss";
87 changes: 87 additions & 0 deletions src/lib/styles/global/menu.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
@use "../mixins/media";

:root {
div.split-pane,
div.stretch-pane {
div[role="menu"]:first-child {
--menu-width: var(--menu-expanded-width);

button {
&.menu-expand,
&.menu-collapse {
opacity: 0;
visibility: hidden;
transition: opacity var(--animation-time-long);

padding: var(--padding-1_5x);
}

&.menu-collapse {
position: absolute;
right: 0;
bottom: 64px;
transform: rotate(-180deg);
}
}

[role="menuitem"] {
span,
div {
opacity: 1;
transition: opacity var(--animation-time-normal);
}
}

.menu-background {
visibility: visible;
opacity: 1;
transition: opacity var(--animation-time-normal);
}
}
}

&[menu="collapsed"] {
div.split-pane,
div.stretch-pane {
div[role="menu"]:first-child:not(.open) {
--menu-width: var(--menu-collapsed-width);

.inner {
overflow-x: hidden;
}

@include media.min-width(large) {
button.menu-expand {
opacity: 1;
visibility: visible;
}
}

[role="menuitem"] {
span,
div {
opacity: 0;
}
}

.menu-background *:not(.background) {
opacity: 0;
}
}
}
}

&:not([menu="collapsed"]) {
div.split-pane,
div.stretch-pane {
div[role="menu"]:first-child {
@include media.min-width(large) {
button.menu-collapse {
opacity: 1;
visibility: visible;
}
}
}
}
}
}
4 changes: 4 additions & 0 deletions src/lib/types/menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum Menu {
COLLAPSED = "collapsed",
EXPANDED = "expanded",
}
43 changes: 43 additions & 0 deletions src/lib/utils/menu.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Menu } from "$lib/types/menu";
import { isNode } from "$lib/utils/env.utils";
import { enumFromStringExists } from "./enum.utils";

export const MENU_ATTRIBUTE = "menu";
export const LOCALSTORAGE_MENU_KEY = "nnsMenu";

export const initMenu = (): Menu | undefined => {
// No DOM therefore cannot guess the menu
if (isNode()) {
return undefined;
}

const menu: string | null =
document.documentElement.getAttribute(MENU_ATTRIBUTE);

const initialMenu: Menu = enumFromStringExists({
obj: Menu,
value: menu,
})
? (menu as Menu)
: Menu.EXPANDED;

applyMenu({ menu: initialMenu, preserve: false });

return initialMenu;
};

export const applyMenu = ({
menu,
preserve = true,
}: {
menu: Menu;
preserve?: boolean;
}) => {
const { documentElement } = document;

documentElement.setAttribute(MENU_ATTRIBUTE, menu);

if (preserve) {
localStorage.setItem(LOCALSTORAGE_MENU_KEY, JSON.stringify(menu));
}
};

0 comments on commit 969b784

Please sign in to comment.