Add initial work on responsive nav and customisable layout
This commit is contained in:
parent
61912fd7cd
commit
50d1ba6f37
|
@ -34,6 +34,7 @@
|
|||
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "^0.9.47",
|
||||
"@spectrum-css/link": "^3.1.3",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
"apexcharts": "^3.22.1",
|
||||
|
|
|
@ -1,92 +1,298 @@
|
|||
<script>
|
||||
import Navigation from "./Navigation.svelte"
|
||||
import { ActionButton } from "@budibase/bbui"
|
||||
import { getContext } from "svelte"
|
||||
import { ActionButton, Heading } from "@budibase/bbui"
|
||||
|
||||
const { styleable, transition } = getContext("sdk")
|
||||
const { styleable, linkable } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
export let title = ""
|
||||
export let hideTitle = false
|
||||
export let logoUrl = "https://i.imgur.com/Xhdt1YP.png"
|
||||
export let hideLogo = false
|
||||
export let navigation = "Top"
|
||||
|
||||
export let links = [
|
||||
{ text: "Some Text", url: "/" },
|
||||
{ text: "Some Text", url: "/" },
|
||||
]
|
||||
const navigationTypes = new Map([
|
||||
["Top", "top"],
|
||||
["Left", "left"],
|
||||
["None", ""],
|
||||
])
|
||||
|
||||
const navigationClasses = {
|
||||
Top: "top",
|
||||
Left: "left",
|
||||
None: "none",
|
||||
}
|
||||
|
||||
$: type = navigationClasses[navigation] || "none"
|
||||
let mobileOpen = false
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="container {navigationTypes.get(navigation)}"
|
||||
in:transition={{ type: $component.transition }}
|
||||
use:styleable={$component.styles}
|
||||
>
|
||||
{#if navigationTypes.get(navigation)}
|
||||
<div class="nav">
|
||||
<div class="logo">
|
||||
{#if !hideLogo}
|
||||
<img src="https://i.imgur.com/Xhdt1YP.png" alt={title} height="48" />
|
||||
{/if}
|
||||
{#if !hideTitle}
|
||||
<span>{title}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="links">
|
||||
<Navigation {navigation} {links} />
|
||||
</div>
|
||||
<div class="portal">
|
||||
<ActionButton quiet icon="Apps" on:click />
|
||||
<div class="layout layout--{type}" use:styleable={$component.styles}>
|
||||
{#if type !== "none"}
|
||||
<div class="nav-wrapper">
|
||||
<div class="nav nav--{type}">
|
||||
<div class="burger">
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="ShowMenu"
|
||||
on:click={() => (mobileOpen = !mobileOpen)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="logo">
|
||||
{#if !hideLogo}
|
||||
<img src="https://i.imgur.com/Xhdt1YP.png" alt={title} />
|
||||
{/if}
|
||||
{#if !hideTitle}
|
||||
<Heading>{title}</Heading>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="portal">
|
||||
<ActionButton quiet icon="Apps" on:click />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mobile-click-handler"
|
||||
class:visible={mobileOpen}
|
||||
on:click={() => (mobileOpen = false)}
|
||||
/>
|
||||
<div class="links" class:visible={mobileOpen}>
|
||||
{#each links as { text, url, external }}
|
||||
{#if external}
|
||||
<a class="link" href={url}>{text}</a>
|
||||
{:else}
|
||||
<a class="link" href={url} use:linkable>{text}</a>
|
||||
{/if}
|
||||
{/each}
|
||||
<div class="close">
|
||||
<ActionButton
|
||||
quiet
|
||||
icon="Close"
|
||||
on:click={() => (mobileOpen = false)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="main">
|
||||
<slot />
|
||||
<div class="main-wrapper">
|
||||
<div class="main">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
/* Main components */
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-gap: 16px;
|
||||
grid-template-columns: 1fr;
|
||||
position: relative;
|
||||
grid-template-columns: 1fr;
|
||||
min-height: 100%;
|
||||
}
|
||||
.nav-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
background: white;
|
||||
}
|
||||
.nav {
|
||||
flex: 1 1 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-areas: "burger logo portal";
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-m);
|
||||
padding: var(--spacing-xl);
|
||||
max-width: 1400px;
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
.links {
|
||||
grid-area: burger;
|
||||
.main-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
}
|
||||
.logo {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
grid-area: logo;
|
||||
}
|
||||
.portal {
|
||||
grid-area: portal;
|
||||
display: grid;
|
||||
justify-content: end;
|
||||
.main {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
max-width: 1400px;
|
||||
}
|
||||
|
||||
/* Nav components */
|
||||
.burger {
|
||||
display: none;
|
||||
}
|
||||
.logo {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xl);
|
||||
grid-column: 1;
|
||||
}
|
||||
.logo img {
|
||||
height: 48px;
|
||||
}
|
||||
.portal {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
grid-column: 2;
|
||||
}
|
||||
.links {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: var(--spacing-l);
|
||||
grid-column: 1 / 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
.link {
|
||||
color: var(--spectrum-alias-text-color);
|
||||
font-size: var(--spectrum-alias-font-size-default);
|
||||
font-weight: 600;
|
||||
transition: color 130ms ease-out;
|
||||
}
|
||||
.link:hover {
|
||||
color: var(--spectrum-alias-text-color-hover);
|
||||
}
|
||||
.close {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: var(--spacing-m);
|
||||
right: var(--spacing-m);
|
||||
}
|
||||
.mobile-click-handler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Desktop nav overrides */
|
||||
@media (min-width: 600px) {
|
||||
.nav,
|
||||
.logo {
|
||||
display: initial;
|
||||
}
|
||||
.top {
|
||||
.layout--top {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
.left {
|
||||
grid-template-columns: 200px 1fr;
|
||||
.layout--left {
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.nav--top {
|
||||
grid-template-rows: auto auto;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-xl);
|
||||
}
|
||||
.nav--left {
|
||||
grid-template-rows: auto 1fr;
|
||||
width: 250px;
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
|
||||
.nav--top .links {
|
||||
margin-top: var(--spacing-l);
|
||||
}
|
||||
.nav--left .logo {
|
||||
gap: var(--spacing-m);
|
||||
}
|
||||
.nav--left .logo img {
|
||||
height: 28px;
|
||||
}
|
||||
.nav--left .logo :global(h1) {
|
||||
font-size: var(--spectrum-global-dimension-font-size-100);
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.nav--left .links {
|
||||
margin-top: var(--spacing-l);
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
}
|
||||
.layout--left .main-wrapper {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile nav overrides */
|
||||
@media (max-width: 600px) {
|
||||
/* Always use top layout on mobile */
|
||||
.layout {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
/* Show close button in drawer */
|
||||
.close {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Force standard top bar */
|
||||
.nav {
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-xl);
|
||||
grid-template-columns: auto auto auto;
|
||||
grid-template-rows: auto;
|
||||
padding: var(--spacing-m);
|
||||
}
|
||||
.burger {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
grid-column: 1;
|
||||
}
|
||||
.logo {
|
||||
grid-column: 2;
|
||||
}
|
||||
.logo img {
|
||||
height: 36px;
|
||||
}
|
||||
.logo :global(h1) {
|
||||
display: none;
|
||||
}
|
||||
.portal {
|
||||
grid-column: 3;
|
||||
}
|
||||
|
||||
/* Transform links into drawer */
|
||||
.links {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: -250px;
|
||||
transform: translateX(0);
|
||||
width: 250px;
|
||||
transition: transform 0.26s ease-in-out, opacity 0.26s ease-in-out;
|
||||
height: 100vh;
|
||||
opacity: 0;
|
||||
background: white;
|
||||
z-index: 999;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
padding: var(--spacing-xl);
|
||||
}
|
||||
.link {
|
||||
width: calc(100% - 30px);
|
||||
}
|
||||
.links.visible {
|
||||
opacity: 1;
|
||||
transform: translateX(250px);
|
||||
box-shadow: 0 0 40px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.mobile-click-handler.visible {
|
||||
position: fixed;
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: 998;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
export let navigation
|
||||
export let links
|
||||
|
||||
let mobileOpen = false
|
||||
export let mobileOpen = false
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4"
|
||||
integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w==
|
||||
|
||||
"@budibase/bbui@^0.9.41":
|
||||
version "0.9.45"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.45.tgz#c37e84ffbf99daf0ebaa5c19b9109e7222463591"
|
||||
integrity sha512-+wojKap0kieYoeCqhah1V9EswVbR+Pg1k9Nlw1n/zTsuGtjA0kUH652yKjz7zNzZgFm+s5oYS1CoPieIMehhSw==
|
||||
"@budibase/bbui@^0.9.47":
|
||||
version "0.9.47"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.47.tgz#d8664a05203432d522cd91a0bad1cdd8518baf93"
|
||||
integrity sha512-LXvJCgUSoc4EJKafBaKfUzU4GUOQGmts/8F4V6LTFtTyMZavgq2/KFAgPbR3QeYvidLsshtwop/pQfoszXTQnQ==
|
||||
dependencies:
|
||||
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
|
||||
"@spectrum-css/actionbutton" "^1.0.1"
|
||||
|
@ -140,7 +140,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@spectrum-css/label/-/label-2.0.10.tgz#2368651d7636a19385b5d300cdf6272db1916001"
|
||||
integrity sha512-xCbtEiQkZIlLdWFikuw7ifDCC21DOC/KMgVrrVJHXFc4KRQe9LTZSqmGF3tovm+CSq1adE59mYoTbojVQ9YuEQ==
|
||||
|
||||
"@spectrum-css/link@^3.1.1":
|
||||
"@spectrum-css/link@^3.1.1", "@spectrum-css/link@^3.1.3":
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.3.tgz#b0e560a7e0acdb4a2b329b6669696aa3438f5993"
|
||||
integrity sha512-8Pmy5d73MwKcATTPaj+fSrZYnIw7GmfX40AvpC1xx5LauOxsbUb4AVNp1kn2H8rrOBmxF7czyhoBBhEiv66QUg==
|
||||
|
|
Loading…
Reference in New Issue