diff --git a/src/frontend/src/components/authenticateBox.ts b/src/frontend/src/components/authenticateBox.ts
index 070d6304d1..df75a76231 100644
--- a/src/frontend/src/components/authenticateBox.ts
+++ b/src/frontend/src/components/authenticateBox.ts
@@ -31,7 +31,7 @@ import {
signInIcon,
} from "./icons";
import { withLoader } from "./loader";
-import { mainWindow } from "./mainWindow";
+import { mainWindowWithSidebar } from "./mainWindowWithSidebar";
import { promptUserNumber } from "./promptUserNumber";
import copyJson from "./authenticateBox.json";
@@ -322,7 +322,7 @@ export const authenticate = async (
// Wrap the template with header & footer and render the page
const page = (slot: TemplateResult) => {
- const template = mainWindow({
+ const template = mainWindowWithSidebar({
slot: html`
Internet Identity
${slot}`,
diff --git a/src/frontend/src/components/mainWindowWithSidebar.ts b/src/frontend/src/components/mainWindowWithSidebar.ts
new file mode 100644
index 0000000000..60fdb5fe81
--- /dev/null
+++ b/src/frontend/src/components/mainWindowWithSidebar.ts
@@ -0,0 +1,129 @@
+import { html, TemplateResult } from "lit-html";
+import { ifDefined } from "lit-html/directives/if-defined.js";
+import { footer } from "./footer";
+import { icLogo } from "./icons";
+
+import { getDapps } from "$src/flows/dappsExplorer/dapps";
+import { dappsHeader } from "$src/flows/dappsExplorer/teaser";
+import { shuffleArray } from "$src/utils/utils";
+
+/** dapps visual used in sidebar */
+const dappsVisual = (): TemplateResult => {
+ const dapps = shuffleArray(getDapps());
+ return dappsHeader({
+ dapps,
+ clickable: false,
+ });
+};
+
+/**
+ * main window template
+ *
+ * To avoid having to repeat the same structure in every page,
+ * we use this component to wrap the content of each page.
+ * This way, we can change the structure of the main window
+ * in one place.
+ *
+ * It is a component that includes the logo, the footer, and the container.
+ *
+ */
+export const mainWindowWithSidebar = ({
+ slot,
+ id,
+ showFooter = true,
+ showLogo = true,
+ isWideContainer = false,
+ additionalContainerClasses = [],
+}: {
+ slot: TemplateResult;
+ id?: string;
+ showFooter?: boolean;
+ showLogo?: boolean;
+ isWideContainer?: boolean;
+ additionalContainerClasses?: string[];
+ HTMLwrapperTag?: string;
+}): TemplateResult => {
+ const containerClasses = ["l-container"];
+ if (isWideContainer === true) {
+ containerClasses.push("l-container--wide");
+ }
+ if (additionalContainerClasses.length > 0) {
+ containerClasses.push(...additionalContainerClasses);
+ }
+ // we do not use the logo from the icons file because it duplicates the the ID's
+ // (also hides those corresponding IDs in the other instances of the logos when the sidebar is not visible)
+ return html`
+
+ `;
+};
diff --git a/src/frontend/src/styles/main.css b/src/frontend/src/styles/main.css
index c5f1c18aeb..dd86e72644 100644
--- a/src/frontend/src/styles/main.css
+++ b/src/frontend/src/styles/main.css
@@ -139,6 +139,7 @@
--vs-line-height: 1.4;
--vs-border-radius: 0.8rem;
+ --vs-gutter-relative: 5vmax;
/*
* reference tokens
@@ -167,6 +168,9 @@
--rc-background: var(--rc-light);
--rc-background-transparent: var(--rc-light-transparent);
+ --rc-sidebar: var(--vc-brand-purple);
+ --rc-onSidebar: var(--vc-snow);
+
--rc-footer: var(--rc-dark);
--rc-onFooter: var(--rc-light);
@@ -242,6 +246,9 @@
--rg-brand-bruised: var(--vc-brand-blue) 50%, var(--vc-brand-purple) 90%;
/* reference tokens: sizes */
+ --rs-bezel-layout: var(--vs-gutter-relative);
+ --rs-bezel-sidebar: calc(var(--vs-gutter-relative) * 0.5);
+
--rs-inline-grid-gap: var(--vs-inline);
--rs-inline-icon-gap: var(--vs-inline);
@@ -611,7 +618,38 @@ a:hover,
flex-direction: column;
align-items: center;
min-height: 100vh;
- padding: 5vmax;
+ padding: var(--vs-gutter-relative);
+}
+
+.l-wrap--sidebar {
+ --sidebar-width: calc(30rem + var(--rs-bezel-sidebar) * 2);
+ padding-left: var(--sidebar-width);
+}
+
+.l-sidebar {
+ position: fixed;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ display: flex;
+ flex-direction: column;
+ width: calc(30rem + var(--rs-bezel-sidebar) * 2);
+ background: var(--rc-sidebar);
+ color: var(--rc-onSidebar);
+ padding: var(--rs-bezel-sidebar);
+}
+
+.l-sidebar__main {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+}
+
+.l-sidebar__decoration {
+ position: relative;
+ margin: 0 calc(var(--rs-bezel-sidebar) * -1)
+ calc(var(--rs-bezel-sidebar) * -1);
}
@media (max-width: 512px) {
@@ -646,6 +684,16 @@ a:hover,
right: 0;
}
+.l-wrap--sidebar .l-footer {
+ left: var(--sidebar-width);
+}
+
+@media (max-width: 512px) {
+ .l-wrap--sidebar .l-footer {
+ left: 0;
+ }
+}
+
/**
* Title with counter and Actions
*/
@@ -1147,6 +1195,10 @@ by all browsers (FF is missing) */
gap: 1em;
}
+.c-logo--sidebar {
+ padding: var(--rs-logo-stack--top) 0 var(--rs-logo-stack--bottom);
+}
+
.c-logo svg {
display: block;
width: 5.5rem;
@@ -2420,6 +2472,18 @@ a.c-action-list__item {
display: none !important;
}
+@media (max-width: 512px) {
+ .is-hidden--mobile {
+ display: none !important;
+ }
+}
+
+@media (min-width: 513px) {
+ .is-hidden--desktop {
+ display: none !important;
+ }
+}
+
.is-visible {
display: block !important;
}