1
0
Fork 0
mirror of synced 2024-09-11 23:16:00 +12:00

Refactor main portal page into multiple components

This commit is contained in:
Andrew Kingston 2023-01-11 10:13:19 +00:00
parent 34adcdcddf
commit e9d20a885b
7 changed files with 236 additions and 169 deletions

View file

@ -37,5 +37,10 @@
.side-nav:not(.show-mobile) {
display: none;
}
.side-nav.show-mobile :global(.side-nav) {
border-bottom: var(--border-light);
margin: 0 -24px;
padding: 0 24px 32px 24px;
}
}
</style>

View file

@ -23,12 +23,4 @@
color: var(--spectrum-global-color-gray-700);
margin-bottom: var(--spacing-m);
}
@media (max-width: 640px) {
.side-nav {
border-bottom: var(--border-light);
margin: 0 -24px;
padding: 0 24px 32px 24px;
}
}
</style>

View file

@ -0,0 +1,13 @@
<script>
import Logo from "assets/bb-emblem.svg"
import { goto } from "@roxi/routify"
</script>
<img src={Logo} alt="Budibase Logo" on:click={() => $goto("./apps")} />
<style>
img {
width: 30px;
height: 30px;
}
</style>

View file

@ -0,0 +1,79 @@
<script>
import { Layout } from "@budibase/bbui"
import { SideNav, SideNavItem } from "components/portal/page"
import { createEventDispatcher } from "svelte"
import { isActive } from "@roxi/routify"
import UpgradeButton from "./UpgradeButton.svelte"
import { fade } from "svelte/transition"
import Logo from "./Logo.svelte"
export let visible = false
export let menu
const dispatch = createEventDispatcher()
const close = () => dispatch("close")
</script>
{#if visible}
<div
class="mobile-nav-underlay"
transition:fade={{ duration: 130 }}
on:click={close}
/>
{/if}
<div class="mobile-nav" class:visible>
<Layout noPadding gap="M">
<div on:click={close}>
<Logo />
</div>
<SideNav>
{#each menu as { title, href }}
<SideNavItem
text={title}
url={href}
active={$isActive(href)}
on:click={close}
/>
{/each}
</SideNav>
<div>
<UpgradeButton />
</div>
</Layout>
</div>
<style>
.mobile-nav {
display: none;
}
@media (max-width: 640px) {
.mobile-nav-underlay {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background: rgba(0, 0, 0, 0.5);
}
.mobile-nav {
transform: translateX(-100%);
display: block;
position: absolute;
top: 0;
left: 0;
padding: 16px 24px;
height: 100%;
width: 240px;
background: var(--background);
z-index: 2;
transition: transform 130ms ease-out;
}
.mobile-nav.visible {
transform: translateX(0);
}
}
</style>

View file

@ -0,0 +1,20 @@
<script>
import { Button } from "@budibase/bbui"
import { goto } from "@roxi/routify"
import { auth, admin } from "stores/portal"
</script>
{#if $admin.cloud && $auth?.user?.accountPortalAccess}
<Button
cta
on:click={() => {
$goto($admin.accountPortalUrl + "/portal/upgrade")
}}
>
Upgrade
</Button>
{:else if !$admin.cloud && $auth.isAdmin}
<Button cta on:click={() => $goto("/builder/portal/account/upgrade")}>
Upgrade
</Button>
{/if}

View file

@ -0,0 +1,78 @@
<script>
import { auth } from "stores/portal"
import { ActionMenu, Avatar, MenuItem, Icon, Modal } from "@budibase/bbui"
import { goto } from "@roxi/routify"
import ProfileModal from "components/settings/ProfileModal.svelte"
import ChangePasswordModal from "components/settings/ChangePasswordModal.svelte"
import ThemeModal from "components/settings/ThemeModal.svelte"
import APIKeyModal from "components/settings/APIKeyModal.svelte"
let themeModal
let profileModal
let updatePasswordModal
let apiKeyModal
const logout = async () => {
try {
await auth.logout()
} catch (error) {
// Swallow error and do nothing
}
}
</script>
<ActionMenu align="right" dataCy="user-menu">
<div slot="control" class="user-dropdown">
<Avatar size="L" initials={$auth.initials} url={$auth.user.pictureUrl} />
<Icon size="XL" name="ChevronDown" />
</div>
<MenuItem icon="Moon" on:click={() => themeModal.show()} dataCy="theme">
Theme
</MenuItem>
<MenuItem
icon="UserEdit"
on:click={() => profileModal.show()}
dataCy="user-info"
>
My profile
</MenuItem>
<MenuItem icon="LockClosed" on:click={() => updatePasswordModal.show()}>
Update password
</MenuItem>
<MenuItem icon="Key" on:click={() => apiKeyModal.show()} dataCy="api-key">
View API key
</MenuItem>
<MenuItem icon="UserDeveloper" on:click={() => $goto("../apps")}>
Close developer mode
</MenuItem>
<MenuItem dataCy="user-logout" icon="LogOut" on:click={logout}>
Log out
</MenuItem>
</ActionMenu>
<Modal bind:this={themeModal}>
<ThemeModal />
</Modal>
<Modal bind:this={profileModal}>
<ProfileModal />
</Modal>
<Modal bind:this={updatePasswordModal}>
<ChangePasswordModal />
</Modal>
<Modal bind:this={apiKeyModal}>
<APIKeyModal />
</Modal>
<style>
.user-dropdown {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
gap: var(--spacing-s);
}
.user-dropdown:hover {
cursor: pointer;
filter: brightness(110%);
}
</style>

View file

@ -1,30 +1,15 @@
<script>
import { isActive, redirect, goto, url } from "@roxi/routify"
import {
Icon,
Avatar,
ActionMenu,
MenuItem,
Modal,
notifications,
Tabs,
Tab,
Button,
} from "@budibase/bbui"
import { Icon, notifications, Tabs, Tab } from "@budibase/bbui"
import { organisation, auth, admin as adminStore } from "stores/portal"
import { onMount } from "svelte"
import ProfileModal from "components/settings/ProfileModal.svelte"
import ChangePasswordModal from "components/settings/ChangePasswordModal.svelte"
import ThemeModal from "components/settings/ThemeModal.svelte"
import APIKeyModal from "components/settings/APIKeyModal.svelte"
import Logo from "assets/bb-emblem.svg"
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
import UpgradeButton from "./_components/UpgradeButton.svelte"
import MobileMenu from "./_components/MobileMenu.svelte"
import Logo from "./_components/Logo.svelte"
import UserDropdown from "./_components/UserDropdown.svelte"
let loaded = false
let themeModal
let profileModal
let updatePasswordModal
let apiKeyModal
let mobileMenuVisible = false
let activeTab = "Apps"
@ -91,14 +76,6 @@
return menu
}
const logout = async () => {
try {
await auth.logout()
} catch (error) {
// Swallow error and do nothing
}
}
const showMobileMenu = () => (mobileMenuVisible = true)
const hideMobileMenu = () => (mobileMenuVisible = false)
@ -122,95 +99,31 @@
{#if $auth.user && loaded}
<div class="container">
<div class="nav">
<div class="branding" on:click={() => $goto("./apps")}>
<img src={Logo} alt="Logotype" />
<div class="branding">
<Logo />
</div>
<Tabs selected={activeTab}>
{#each menu as { title, href }}
<Tab {title} on:click={() => $goto(href)} />
{/each}
</Tabs>
<div class="toolbar">
<div class="mobile-toggle">
<Icon hoverable name="ShowMenu" on:click={showMobileMenu} />
</div>
{#if $adminStore.cloud && $auth?.user?.accountPortalAccess}
<Button
cta
on:click={() => {
$goto($adminStore.accountPortalUrl + "/portal/upgrade")
}}
>
Upgrade
</Button>
{:else if !$adminStore.cloud && $auth.isAdmin}
<Button cta on:click={() => $goto("/builder/portal/account/upgrade")}>
Upgrade
</Button>
{/if}
<div class="user-dropdown">
<ActionMenu align="right" dataCy="user-menu">
<div slot="control" class="avatar">
<Avatar
size="L"
initials={$auth.initials}
url={$auth.user.pictureUrl}
/>
<Icon size="XL" name="ChevronDown" />
</div>
<MenuItem
icon="Moon"
on:click={() => themeModal.show()}
dataCy="theme"
>
Theme
</MenuItem>
<MenuItem
icon="UserEdit"
on:click={() => profileModal.show()}
dataCy="user-info"
>
My profile
</MenuItem>
<MenuItem
icon="LockClosed"
on:click={() => updatePasswordModal.show()}
>
Update password
</MenuItem>
<MenuItem
icon="Key"
on:click={() => apiKeyModal.show()}
dataCy="api-key"
>
View API key
</MenuItem>
<MenuItem icon="UserDeveloper" on:click={() => $goto("../apps")}>
Close developer mode
</MenuItem>
<MenuItem dataCy="user-logout" icon="LogOut" on:click={logout}>
Log out
</MenuItem>
</ActionMenu>
</div>
<div class="desktop">
<Tabs selected={activeTab}>
{#each menu as { title, href }}
<Tab {title} on:click={() => $goto(href)} />
{/each}
</Tabs>
</div>
<div class="mobile">
<Icon hoverable name="ShowMenu" on:click={showMobileMenu} />
</div>
<div class="desktop">
<UpgradeButton />
</div>
<div class="dropdown">
<UserDropdown />
</div>
</div>
<div class="main">
<slot />
</div>
<MobileMenu visible={mobileMenuVisible} {menu} on:close={hideMobileMenu} />
</div>
<Modal bind:this={themeModal}>
<ThemeModal />
</Modal>
<Modal bind:this={profileModal}>
<ProfileModal />
</Modal>
<Modal bind:this={updatePasswordModal}>
<ChangePasswordModal />
</Modal>
<Modal bind:this={apiKeyModal}>
<APIKeyModal />
</Modal>
{/if}
<style>
@ -226,57 +139,30 @@
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: stretch;
align-items: center;
border-bottom: var(--border-light);
padding: 0 24px;
gap: 24px;
position: relative;
}
/* Customise tabs appearance*/
.nav :global(.spectrum-Tabs) {
margin-bottom: -2px;
padding: 7px 0;
flex: 1 1 auto;
}
.nav :global(.spectrum-Tabs-content) {
display: none;
}
.nav :global(.spectrum-Tabs-itemLabel) {
font-weight: 600;
}
.branding {
display: grid;
place-items: center;
}
.avatar {
display: grid;
grid-template-columns: auto auto;
place-items: center;
grid-gap: var(--spacing-s);
}
.avatar:hover {
cursor: pointer;
filter: brightness(110%);
}
.toolbar {
flex: 1 1 auto;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
gap: 24px;
}
.mobile-toggle {
display: none;
}
.user-dropdown {
display: flex;
flex-direction: row;
justify-content: flex-end;
}
img {
width: 30px;
height: 30px;
}
.main {
flex: 1 1 auto;
display: flex;
@ -285,35 +171,29 @@
align-items: stretch;
overflow: auto;
}
.mobile {
display: none;
}
.desktop {
display: contents;
}
@media (max-width: 640px) {
.mobile {
display: contents;
}
.desktop {
display: none;
}
.nav {
flex: 0 0 52px;
}
.toolbar {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.branding {
position: absolute;
left: 50%;
top: 50%;
transform: translateY(-50%) translateX(-50%);
}
.nav :global(.spectrum-Tabs) {
display: none !important;
}
.toolbar :global(.spectrum-Button) {
display: none;
}
.mobile-toggle {
display: block;
}
.mobile-toggle,
.user-dropdown {
flex: 0 1 0;
transform: translateX(-50%) translateY(-50%);
}
}
</style>