forked from tsai/budibase
92 changed files with 679 additions and 3762 deletions
@ -1,62 +1,16 @@ |
|||
<script> |
|||
export let forAttr = "", |
|||
extraSmall = false, |
|||
small = false, |
|||
medium = false, |
|||
large = false, |
|||
extraLarge = false, |
|||
white = false, |
|||
grey = false, |
|||
black = false |
|||
import "@spectrum-css/fieldlabel/dist/index-vars.css" |
|||
|
|||
export let size = "M" |
|||
</script> |
|||
|
|||
<label |
|||
class="bb-label" |
|||
class:extraSmall |
|||
class:small |
|||
class:medium |
|||
class:large |
|||
class:extraLarge |
|||
class:white |
|||
class:grey |
|||
class:black |
|||
for={forAttr} |
|||
> |
|||
<label class={`spectrum-FieldLabel spectrum-FieldLabel--size${size}`}> |
|||
<slot /> |
|||
</label> |
|||
|
|||
<style> |
|||
.bb-label { |
|||
font-family: var(--font-sans); |
|||
font-weight: 500; |
|||
text-rendering: var(--text-render); |
|||
color: var(--ink); |
|||
font-size: var(--font-size-s); |
|||
margin-bottom: var(--spacing-s); |
|||
display: block; |
|||
} |
|||
.extraSmall { |
|||
font-size: var(--font-size-xs); |
|||
} |
|||
.small { |
|||
font-size: var(--font-size-s); |
|||
} |
|||
.medium { |
|||
font-size: var(--font-size-m); |
|||
} |
|||
.large { |
|||
font-size: var(--font-size-l); |
|||
} |
|||
.extraLarge { |
|||
font-size: var(--font-size-xl); |
|||
} |
|||
.white { |
|||
color: white; |
|||
} |
|||
.grey { |
|||
color: var(--grey-6); |
|||
} |
|||
.black { |
|||
color: var(--ink); |
|||
label { |
|||
padding: 0; |
|||
white-space: nowrap; |
|||
} |
|||
</style> |
|||
|
|||
@ -0,0 +1,64 @@ |
|||
export const gradient = (node, config = {}) => { |
|||
const defaultConfig = { |
|||
points: 10, |
|||
saturation: 0.8, |
|||
lightness: 0.75, |
|||
softness: 0.8, |
|||
} |
|||
|
|||
// Applies a gradient background
|
|||
const createGradient = config => { |
|||
config = { |
|||
...defaultConfig, |
|||
...config, |
|||
} |
|||
const { saturation, lightness, softness, points } = config |
|||
|
|||
// Generates a random number between min and max
|
|||
const rand = (min, max) => { |
|||
return Math.round(min + Math.random() * (max - min)) |
|||
} |
|||
|
|||
// Generates a random HSL colour using the options specified
|
|||
const randomHSL = () => { |
|||
const lowerSaturation = Math.min(100, saturation * 100) |
|||
const upperSaturation = Math.min(100, (saturation + 0.2) * 100) |
|||
const lowerLightness = Math.min(100, lightness * 100) |
|||
const upperLightness = Math.min(100, (lightness + 0.2) * 100) |
|||
const hue = rand(0, 360) |
|||
const sat = `${rand(lowerSaturation, upperSaturation)}%` |
|||
const light = `${rand(lowerLightness, upperLightness)}%` |
|||
return `hsl(${hue},${sat},${light})` |
|||
} |
|||
|
|||
// Generates a radial gradient stop point
|
|||
const randomGradientPoint = () => { |
|||
const lowerTransparency = Math.min(100, softness * 100) |
|||
const upperTransparency = Math.min(100, (softness + 0.2) * 100) |
|||
const transparency = rand(lowerTransparency, upperTransparency) |
|||
return ( |
|||
`radial-gradient(` + |
|||
`at ${rand(10, 90)}% ${rand(10, 90)}%,` + |
|||
`${randomHSL()} 0,` + |
|||
`transparent ${transparency}%)` |
|||
) |
|||
} |
|||
|
|||
let css = `opacity:0.9;background-color:${randomHSL()};background-image:` |
|||
for (let i = 0; i < points - 1; i++) { |
|||
css += `${randomGradientPoint()},` |
|||
} |
|||
css += `${randomGradientPoint()};` |
|||
node.style = css |
|||
} |
|||
|
|||
// Apply the initial gradient
|
|||
createGradient(config) |
|||
|
|||
return { |
|||
// Apply a new gradient
|
|||
update: config => { |
|||
createGradient(config) |
|||
}, |
|||
} |
|||
} |
|||
@ -1,50 +1,25 @@ |
|||
<script> |
|||
import { onMount } from "svelte" |
|||
import AppCard from "./AppCard.svelte" |
|||
import { Heading, Divider } from "@budibase/bbui" |
|||
import Spinner from "components/common/Spinner.svelte" |
|||
import { get } from "builderStore/api" |
|||
import { apps } from "stores/portal" |
|||
|
|||
let promise = getApps() |
|||
|
|||
async function getApps() { |
|||
const res = await get("/api/applications") |
|||
const json = await res.json() |
|||
|
|||
if (res.ok) { |
|||
return json |
|||
} else { |
|||
throw new Error(json) |
|||
} |
|||
} |
|||
onMount(apps.load) |
|||
</script> |
|||
|
|||
<div class="root"> |
|||
<Heading size="M">Your Apps</Heading> |
|||
<Divider size="M" /> |
|||
{#await promise} |
|||
<div class="spinner-container"> |
|||
<Spinner size="30" /> |
|||
</div> |
|||
{:then apps} |
|||
<div class="apps"> |
|||
{#each apps as app} |
|||
<AppCard {...app} /> |
|||
{/each} |
|||
</div> |
|||
{:catch err} |
|||
<h1 style="color:red">{err}</h1> |
|||
{/await} |
|||
</div> |
|||
{#if $apps.length} |
|||
<div class="appList"> |
|||
{#each $apps as app} |
|||
<AppCard {...app} /> |
|||
{/each} |
|||
</div> |
|||
{:else} |
|||
<div>No apps</div> |
|||
{/if} |
|||
|
|||
<style> |
|||
.root { |
|||
margin-top: 10px; |
|||
} |
|||
.apps { |
|||
margin-top: var(--layout-m); |
|||
.appList { |
|||
display: grid; |
|||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); |
|||
grid-gap: var(--layout-s); |
|||
justify-content: start; |
|||
grid-gap: 50px; |
|||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); |
|||
} |
|||
</style> |
|||
|
|||
@ -1,15 +0,0 @@ |
|||
<script> |
|||
import { Button, Modal } from "@budibase/bbui" |
|||
import BuilderSettingsModal from "./BuilderSettingsModal.svelte" |
|||
|
|||
let modal |
|||
</script> |
|||
|
|||
<div> |
|||
<Button primary quiet icon="Settings" text on:click={modal.show}> |
|||
Settings |
|||
</Button> |
|||
</div> |
|||
<Modal bind:this={modal} width="30%"> |
|||
<BuilderSettingsModal /> |
|||
</Modal> |
|||
@ -1,6 +0,0 @@ |
|||
<script> |
|||
import { Button } from "@budibase/bbui" |
|||
import { auth } from "stores/backend" |
|||
</script> |
|||
|
|||
<Button primary quiet text icon="LogOut" on:click={auth.logout}>Log Out</Button> |
|||
@ -1,29 +0,0 @@ |
|||
<script> |
|||
import { onMount } from "svelte" |
|||
import { goto } from "@roxi/routify" |
|||
import { |
|||
SideNavigation as Navigation, |
|||
SideNavigationItem as Item, |
|||
} from "@budibase/bbui" |
|||
import { admin } from "stores/portal" |
|||
import LoginForm from "components/login/LoginForm.svelte" |
|||
import BuilderSettingsButton from "components/start/BuilderSettingsButton.svelte" |
|||
import LogoutButton from "components/start/LogoutButton.svelte" |
|||
import Logo from "/assets/budibase-logo.svg" |
|||
import api from "builderStore/api" |
|||
|
|||
let checklist |
|||
|
|||
onMount(async () => { |
|||
await admin.init() |
|||
if (!$admin?.checklist?.adminUser) { |
|||
$goto("./admin") |
|||
} else { |
|||
$goto("./portal") |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
{#if $admin.checklist} |
|||
<slot /> |
|||
{/if} |
|||
@ -0,0 +1,27 @@ |
|||
<script> |
|||
import { onMount } from "svelte" |
|||
import { goto } from "@roxi/routify" |
|||
import { auth } from "stores/backend" |
|||
import { admin } from "stores/portal" |
|||
|
|||
let checked = false |
|||
|
|||
onMount(async () => { |
|||
await admin.init() |
|||
await auth.checkAuth() |
|||
if (!$admin?.checklist?.adminUser) { |
|||
$goto("./admin") |
|||
} |
|||
checked = true |
|||
}) |
|||
|
|||
$: { |
|||
if (checked && !$auth.user) { |
|||
$goto("./auth/login") |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
{#if checked} |
|||
<slot /> |
|||
{/if} |
|||
@ -0,0 +1,4 @@ |
|||
<script> |
|||
import { goto } from "@roxi/routify" |
|||
$goto("./login") |
|||
</script> |
|||
@ -0,0 +1,5 @@ |
|||
<script> |
|||
import LoginForm from "components/login/LoginForm.svelte" |
|||
</script> |
|||
|
|||
<LoginForm /> |
|||
@ -0,0 +1,4 @@ |
|||
<script> |
|||
import { goto } from "@roxi/routify" |
|||
$goto("../portal") |
|||
</script> |
|||
@ -0,0 +1,4 @@ |
|||
<script> |
|||
import { goto } from "@roxi/routify" |
|||
$goto("./portal") |
|||
</script> |
|||
@ -0,0 +1,159 @@ |
|||
<script> |
|||
import { isActive, goto } from "@roxi/routify" |
|||
import { onMount } from "svelte" |
|||
import { |
|||
Icon, |
|||
Avatar, |
|||
Search, |
|||
Layout, |
|||
SideNavigation as Navigation, |
|||
SideNavigationItem as Item, |
|||
ActionMenu, |
|||
MenuItem, |
|||
Modal, |
|||
} from "@budibase/bbui" |
|||
import ConfigChecklist from "components/common/ConfigChecklist.svelte" |
|||
import { organisation, apps } from "stores/portal" |
|||
import { auth } from "stores/backend" |
|||
import BuilderSettingsModal from "components/start/BuilderSettingsModal.svelte" |
|||
|
|||
organisation.init() |
|||
apps.load() |
|||
|
|||
let orgName |
|||
let orgLogo |
|||
let user |
|||
let oldSettingsModal |
|||
|
|||
async function getInfo() { |
|||
// fetch orgInfo |
|||
orgName = "ACME Inc." |
|||
orgLogo = "https://via.placeholder.com/150" |
|||
user = { name: "John Doe" } |
|||
} |
|||
|
|||
onMount(getInfo) |
|||
|
|||
let menu = [ |
|||
{ title: "Apps", href: "/app/portal/apps" }, |
|||
{ title: "Drafts", href: "/app/portal/drafts" }, |
|||
{ title: "Users", href: "/app/portal/users", heading: "Manage" }, |
|||
{ title: "Groups", href: "/app/portal/groups" }, |
|||
{ title: "Auth", href: "/app/portal/oauth" }, |
|||
{ title: "Email", href: "/app/portal/email" }, |
|||
{ |
|||
title: "General", |
|||
href: "/app/portal/settings/general", |
|||
heading: "Settings", |
|||
}, |
|||
{ title: "Theming", href: "/app/portal/theming" }, |
|||
{ title: "Account", href: "/app/portal/account" }, |
|||
] |
|||
</script> |
|||
|
|||
<div class="container"> |
|||
<div class="nav"> |
|||
<Layout paddingX="L" paddingY="L"> |
|||
<div class="branding"> |
|||
<div class="name" on:click={() => $goto("./apps")}> |
|||
<img |
|||
src={$organisation?.logoUrl || "https://i.imgur.com/ZKyklgF.png"} |
|||
alt="Logotype" |
|||
/> |
|||
<span>{$organisation?.company || "Budibase"}</span> |
|||
</div> |
|||
<div class="onboarding"> |
|||
<ConfigChecklist /> |
|||
</div> |
|||
</div> |
|||
<div class="menu"> |
|||
<Navigation> |
|||
{#each menu as { title, href, heading }} |
|||
<Item selected={$isActive(href)} {href} {heading}>{title}</Item> |
|||
{/each} |
|||
</Navigation> |
|||
</div> |
|||
</Layout> |
|||
</div> |
|||
<div class="main"> |
|||
<div class="toolbar"> |
|||
<Search placeholder="Global search" /> |
|||
<ActionMenu align="right"> |
|||
<div slot="control" class="avatar"> |
|||
<Avatar size="M" name="John Doe" /> |
|||
<Icon size="XL" name="ChevronDown" /> |
|||
</div> |
|||
<MenuItem icon="Settings" on:click={oldSettingsModal.show}> |
|||
Old settings |
|||
</MenuItem> |
|||
<MenuItem icon="LogOut" on:click={auth.logout}>Log out</MenuItem> |
|||
</ActionMenu> |
|||
</div> |
|||
<div> |
|||
<slot /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<Modal bind:this={oldSettingsModal} width="30%"> |
|||
<BuilderSettingsModal /> |
|||
</Modal> |
|||
|
|||
<style> |
|||
.container { |
|||
min-height: 100vh; |
|||
display: grid; |
|||
grid-template-columns: 250px 1fr; |
|||
} |
|||
.nav { |
|||
background: var(--background); |
|||
border-right: var(--border-light); |
|||
} |
|||
.main { |
|||
display: grid; |
|||
grid-template-rows: auto 1fr; |
|||
} |
|||
.branding { |
|||
display: grid; |
|||
grid-gap: var(--spacing-s); |
|||
grid-template-columns: auto auto; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
.name { |
|||
display: grid; |
|||
grid-template-columns: auto auto; |
|||
grid-gap: var(--spacing-m); |
|||
align-items: center; |
|||
} |
|||
.name:hover { |
|||
cursor: pointer; |
|||
} |
|||
.avatar { |
|||
display: grid; |
|||
grid-template-columns: auto auto; |
|||
place-items: center; |
|||
grid-gap: var(--spacing-xs); |
|||
} |
|||
.avatar:hover { |
|||
cursor: pointer; |
|||
filter: brightness(110%); |
|||
} |
|||
.toolbar { |
|||
background: var(--background); |
|||
border-bottom: var(--border-light); |
|||
display: grid; |
|||
grid-template-columns: 250px auto; |
|||
justify-content: space-between; |
|||
padding: var(--spacing-m) calc(var(--spacing-xl) * 2); |
|||
align-items: center; |
|||
} |
|||
img { |
|||
width: 28px; |
|||
height: 28px; |
|||
} |
|||
span { |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
font-weight: 500; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,92 @@ |
|||
<script> |
|||
import { |
|||
Heading, |
|||
Layout, |
|||
Button, |
|||
ActionButton, |
|||
ActionGroup, |
|||
ButtonGroup, |
|||
Select, |
|||
Modal, |
|||
} from "@budibase/bbui" |
|||
import AppList from "components/start/AppList.svelte" |
|||
import CreateAppModal from "components/start/CreateAppModal.svelte" |
|||
import api from "builderStore/api" |
|||
import analytics from "analytics" |
|||
import { onMount } from "svelte" |
|||
|
|||
let layout = "grid" |
|||
let modal |
|||
let template |
|||
|
|||
async function checkKeys() { |
|||
const response = await api.get(`/api/keys/`) |
|||
const keys = await response.json() |
|||
if (keys.userId) { |
|||
analytics.identify(keys.userId) |
|||
} |
|||
} |
|||
|
|||
function initiateAppImport() { |
|||
template = { fromFile: true } |
|||
modal.show() |
|||
} |
|||
|
|||
onMount(checkKeys) |
|||
</script> |
|||
|
|||
<Layout noPadding> |
|||
<div class="title"> |
|||
<Heading>Apps</Heading> |
|||
<ButtonGroup> |
|||
<Button secondary on:click={initiateAppImport}>Import app</Button> |
|||
<Button cta on:click={modal.show}>Create new app</Button> |
|||
</ButtonGroup> |
|||
</div> |
|||
<div class="filter"> |
|||
<div class="select"> |
|||
<Select quiet placeholder="Filter by groups" /> |
|||
</div> |
|||
<ActionGroup> |
|||
<ActionButton |
|||
on:click={() => (layout = "grid")} |
|||
selected={layout === "grid"} |
|||
quiet |
|||
icon="ClassicGridView" |
|||
/> |
|||
<ActionButton |
|||
on:click={() => (layout = "table")} |
|||
selected={layout === "table"} |
|||
quiet |
|||
icon="ViewRow" |
|||
/> |
|||
</ActionGroup> |
|||
</div> |
|||
{#if layout === "grid"} |
|||
<AppList /> |
|||
{:else} |
|||
Table |
|||
{/if} |
|||
</Layout> |
|||
<Modal |
|||
bind:this={modal} |
|||
padding={false} |
|||
width="600px" |
|||
on:hide={() => (template = null)} |
|||
> |
|||
<CreateAppModal {template} /> |
|||
</Modal> |
|||
|
|||
<style> |
|||
.title, |
|||
.filter { |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.select { |
|||
width: 110px; |
|||
} |
|||
</style> |
|||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@ -1,108 +0,0 @@ |
|||
<script> |
|||
import { |
|||
SideNavigation as Navigation, |
|||
SideNavigationItem as Item, |
|||
} from "@budibase/bbui" |
|||
import { auth } from "stores/backend" |
|||
import LoginForm from "components/login/LoginForm.svelte" |
|||
import BuilderSettingsButton from "components/start/BuilderSettingsButton.svelte" |
|||
import LogoutButton from "components/start/LogoutButton.svelte" |
|||
import Logo from "/assets/budibase-logo.svg" |
|||
|
|||
let modal |
|||
</script> |
|||
|
|||
<div class="root"> |
|||
<div class="ui-nav"> |
|||
<div class="home-logo"> |
|||
<img src={Logo} alt="Budibase icon" /> |
|||
</div> |
|||
<div class="nav-section"> |
|||
<div class="nav-top"> |
|||
<Navigation> |
|||
<Item href="/builder/" icon="Apps" selected>Apps</Item> |
|||
<Item external href="https://portal.budi.live/" icon="Servers"> |
|||
Hosting |
|||
</Item> |
|||
<Item external href="https://docs.budibase.com/" icon="Book"> |
|||
Documentation |
|||
</Item> |
|||
<Item |
|||
external |
|||
href="https://github.com/Budibase/budibase/discussions" |
|||
icon="PeopleGroup" |
|||
> |
|||
Community |
|||
</Item> |
|||
<Item |
|||
external |
|||
href="https://github.com/Budibase/budibase/issues/new/choose" |
|||
icon="Bug" |
|||
> |
|||
Raise an issue |
|||
</Item> |
|||
</Navigation> |
|||
</div> |
|||
<div class="nav-bottom"> |
|||
<BuilderSettingsButton /> |
|||
<LogoutButton /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="main"> |
|||
<slot /> |
|||
</div> |
|||
</div> |
|||
|
|||
<style> |
|||
.root { |
|||
display: grid; |
|||
grid-template-columns: 260px 1fr; |
|||
height: 100%; |
|||
width: 100%; |
|||
} |
|||
|
|||
.login { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 100%; |
|||
width: 100%; |
|||
} |
|||
|
|||
.main { |
|||
grid-column: 2; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.ui-nav { |
|||
grid-column: 1; |
|||
background-color: var(--background); |
|||
padding: 20px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
border-right: var(--border-light); |
|||
} |
|||
|
|||
.home-logo { |
|||
cursor: pointer; |
|||
height: 40px; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.home-logo img { |
|||
height: 40px; |
|||
} |
|||
|
|||
.nav-section { |
|||
margin: 20px 0 0 0; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: space-between; |
|||
height: 100%; |
|||
} |
|||
|
|||
.nav-bottom :global(> *) { |
|||
margin-top: 5px; |
|||
} |
|||
</style> |
|||
@ -1,123 +0,0 @@ |
|||
<script> |
|||
import api from "builderStore/api" |
|||
import AppList from "components/start/AppList.svelte" |
|||
import { get } from "builderStore/api" |
|||
import CreateAppModal from "components/start/CreateAppModal.svelte" |
|||
import { Button, Heading, Modal, ButtonGroup } from "@budibase/bbui" |
|||
import TemplateList from "components/start/TemplateList.svelte" |
|||
import analytics from "analytics" |
|||
import Banner from "/assets/orange-landscape.png" |
|||
|
|||
let hasKey |
|||
let template |
|||
let modal |
|||
|
|||
async function getApps() { |
|||
const res = await get("/api/applications") |
|||
const json = await res.json() |
|||
|
|||
if (res.ok) { |
|||
return json |
|||
} else { |
|||
throw new Error(json) |
|||
} |
|||
} |
|||
|
|||
async function fetchKeys() { |
|||
const response = await api.get(`/api/keys/`) |
|||
return await response.json() |
|||
} |
|||
|
|||
async function checkIfKeysAndApps() { |
|||
const keys = await fetchKeys() |
|||
const apps = await getApps() |
|||
if (keys.userId) { |
|||
hasKey = true |
|||
analytics.identify(keys.userId) |
|||
} |
|||
} |
|||
|
|||
function selectTemplate(newTemplate) { |
|||
template = newTemplate |
|||
modal.show() |
|||
} |
|||
|
|||
function initiateAppImport() { |
|||
template = { fromFile: true } |
|||
modal.show() |
|||
} |
|||
|
|||
function closeModal() { |
|||
template = null |
|||
modal.hide() |
|||
} |
|||
|
|||
checkIfKeysAndApps() |
|||
</script> |
|||
|
|||
<div class="container"> |
|||
<div class="header"> |
|||
<Heading size="M">Welcome to the Budibase Beta</Heading> |
|||
<ButtonGroup> |
|||
<Button secondary on:click={initiateAppImport}>Import Web App</Button> |
|||
<Button cta on:click={modal.show}>Create New Web App</Button> |
|||
</ButtonGroup> |
|||
</div> |
|||
|
|||
<div class="banner"> |
|||
<img src={Banner} alt="rocket" /> |
|||
<div class="banner-content"> |
|||
Every accomplishment starts with a decision to try. |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- <TemplateList onSelect={selectTemplate} /> --> |
|||
|
|||
<AppList /> |
|||
</div> |
|||
|
|||
<Modal bind:this={modal} padding={false} width="600px" on:hide={closeModal}> |
|||
<CreateAppModal {hasKey} {template} /> |
|||
</Modal> |
|||
|
|||
<style> |
|||
.container { |
|||
display: grid; |
|||
gap: var(--spacing-xl); |
|||
margin: 40px 80px; |
|||
} |
|||
|
|||
.header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.banner { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
position: relative; |
|||
text-align: center; |
|||
color: white; |
|||
border-radius: 16px; |
|||
} |
|||
|
|||
.banner img { |
|||
height: 250px; |
|||
width: 100%; |
|||
border-radius: 5px; |
|||
} |
|||
|
|||
.banner-content { |
|||
position: absolute; |
|||
font-size: 24px; |
|||
color: white; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.button-group { |
|||
display: flex; |
|||
flex-direction: row; |
|||
} |
|||
</style> |
|||
@ -1 +1,4 @@ |
|||
Index route |
|||
<script> |
|||
import { goto } from "@roxi/routify" |
|||
$goto("./app") |
|||
</script> |
|||
|
|||
@ -1,153 +0,0 @@ |
|||
<script> |
|||
import { isActive, url, goto } from "@roxi/routify" |
|||
import { onMount } from "svelte" |
|||
import { |
|||
ActionMenu, |
|||
Checkbox, |
|||
MenuItem, |
|||
Icon, |
|||
Heading, |
|||
Avatar, |
|||
Search, |
|||
Layout, |
|||
ProgressCircle, |
|||
SideNavigation as Navigation, |
|||
SideNavigationItem as Item, |
|||
} from "@budibase/bbui" |
|||
import LoginForm from "components/login/LoginForm.svelte" |
|||
import api from "builderStore/api" |
|||
import ConfigChecklist from "components/common/ConfigChecklist.svelte" |
|||
import { auth } from "stores/backend" |
|||
import { organisation, admin } from "stores/portal" |
|||
|
|||
organisation.init() |
|||
|
|||
let orgName |
|||
let orgLogo |
|||
let user |
|||
|
|||
async function getInfo() { |
|||
// fetch orgInfo |
|||
orgName = "ACME Inc." |
|||
orgLogo = "https://via.placeholder.com/150" |
|||
|
|||
user = { name: "John Doe" } |
|||
} |
|||
|
|||
onMount(getInfo) |
|||
|
|||
let menu = [ |
|||
{ title: "Apps", href: "/portal/apps" }, |
|||
{ title: "Drafts", href: "/portal/drafts" }, |
|||
{ title: "Users", href: "/portal/users", heading: "Manage" }, |
|||
{ title: "Groups", href: "/portal/groups" }, |
|||
{ title: "Auth", href: "/portal/oauth" }, |
|||
{ title: "Email", href: "/portal/email" }, |
|||
{ title: "General", href: "/portal/settings/general", heading: "Settings" }, |
|||
{ title: "Theming", href: "/portal/theming" }, |
|||
{ title: "Account", href: "/portal/account" }, |
|||
] |
|||
</script> |
|||
|
|||
{#if $auth} |
|||
{#if $auth.user} |
|||
<div class="container"> |
|||
<div class="nav"> |
|||
<Layout paddingX="L" paddingY="L"> |
|||
<div class="branding"> |
|||
<div class="name"> |
|||
<img |
|||
src={$organisation?.logoUrl || |
|||
"https://i.imgur.com/ZKyklgF.png"} |
|||
alt="Logotype" |
|||
/> |
|||
<span>{$organisation?.company || "Budibase"}</span> |
|||
</div> |
|||
<div class="onboarding"> |
|||
<ConfigChecklist /> |
|||
</div> |
|||
</div> |
|||
<div class="menu"> |
|||
<Navigation> |
|||
{#each menu as { title, href, heading }} |
|||
<Item selected={$isActive(href)} {href} {heading}>{title}</Item> |
|||
{/each} |
|||
</Navigation> |
|||
</div> |
|||
</Layout> |
|||
</div> |
|||
<div class="main"> |
|||
<div class="toolbar"> |
|||
<Search placeholder="Global search" /> |
|||
<div class="avatar"> |
|||
<Avatar size="M" name="John Doe" /> |
|||
<Icon size="XL" name="ChevronDown" /> |
|||
</div> |
|||
</div> |
|||
<div class="content"> |
|||
<slot /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{:else} |
|||
<section class="login"> |
|||
<LoginForm /> |
|||
</section> |
|||
{/if} |
|||
{/if} |
|||
|
|||
<style> |
|||
.container { |
|||
min-height: 100vh; |
|||
display: grid; |
|||
grid-template-columns: 250px 1fr; |
|||
} |
|||
.nav { |
|||
background: var(--background); |
|||
border-right: var(--border-light); |
|||
} |
|||
.main { |
|||
display: grid; |
|||
grid-template-rows: auto 1fr; |
|||
} |
|||
.branding { |
|||
display: grid; |
|||
grid-gap: var(--spacing-s); |
|||
grid-template-columns: auto auto; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
.name { |
|||
display: grid; |
|||
grid-template-columns: auto auto; |
|||
grid-gap: var(--spacing-m); |
|||
align-items: center; |
|||
} |
|||
.avatar { |
|||
display: grid; |
|||
grid-template-columns: auto auto; |
|||
place-items: center; |
|||
grid-gap: var(--spacing-xs); |
|||
} |
|||
.avatar:hover { |
|||
cursor: pointer; |
|||
filter: brightness(110%); |
|||
} |
|||
.toolbar { |
|||
background: var(--background); |
|||
border-bottom: var(--border-light); |
|||
display: grid; |
|||
grid-template-columns: 250px auto; |
|||
justify-content: space-between; |
|||
padding: var(--spacing-m) calc(var(--spacing-xl) * 2); |
|||
} |
|||
img { |
|||
width: 28px; |
|||
height: 28px; |
|||
} |
|||
span { |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
font-weight: 500; |
|||
} |
|||
</style> |
|||
@ -1,27 +0,0 @@ |
|||
<script> |
|||
import { Heading, Layout } from "@budibase/bbui" |
|||
</script> |
|||
|
|||
<Layout noPadding> |
|||
<div> |
|||
<Heading>Apps</Heading> |
|||
</div> |
|||
<div class="appList"> |
|||
{#each new Array(10) as _} |
|||
<div class="app" /> |
|||
{/each} |
|||
</div> |
|||
</Layout> |
|||
|
|||
<style> |
|||
.appList { |
|||
display: grid; |
|||
grid-gap: 50px; |
|||
grid-template-columns: repeat(auto-fill, 300px); |
|||
} |
|||
.app { |
|||
height: 130px; |
|||
border-radius: 4px; |
|||
background-color: var(--spectrum-global-color-gray-200); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,27 @@ |
|||
import { writable } from "svelte/store" |
|||
import { get } from "builderStore/api" |
|||
|
|||
export function createAppStore() { |
|||
const store = writable([]) |
|||
|
|||
async function load() { |
|||
try { |
|||
const res = await get("/api/applications") |
|||
const json = await res.json() |
|||
if (res.ok && Array.isArray(json)) { |
|||
store.set(json) |
|||
} else { |
|||
store.set([]) |
|||
} |
|||
} catch (error) { |
|||
store.set([]) |
|||
} |
|||
} |
|||
|
|||
return { |
|||
subscribe: store.subscribe, |
|||
load, |
|||
} |
|||
} |
|||
|
|||
export const apps = createAppStore() |
|||
@ -1,2 +1,3 @@ |
|||
export { organisation } from "./organisation" |
|||
export { admin } from "./admin" |
|||
export { apps } from "./apps" |
|||
|
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
Loading…
Reference in new issue