initial home screen redesign layout
This commit is contained in:
parent
68978c5ed1
commit
53557e1bb1
|
@ -1,14 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { gradient } from "actions"
|
import { gradient } from "actions"
|
||||||
import {
|
import { Heading, Button, Icon, ActionMenu, MenuItem } from "@budibase/bbui"
|
||||||
Heading,
|
|
||||||
Button,
|
|
||||||
Icon,
|
|
||||||
ActionMenu,
|
|
||||||
MenuItem,
|
|
||||||
StatusLight,
|
|
||||||
} from "@budibase/bbui"
|
|
||||||
import { processStringSync } from "@budibase/string-templates"
|
|
||||||
|
|
||||||
export let app
|
export let app
|
||||||
export let exportApp
|
export let exportApp
|
||||||
|
@ -28,40 +20,15 @@
|
||||||
</Heading>
|
</Heading>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="desktop">
|
<div class="desktop" />
|
||||||
{#if app.updatedAt}
|
<div class="desktop" />
|
||||||
{processStringSync("Updated {{ duration time 'millisecond' }} ago", {
|
<div class="desktop" />
|
||||||
time: new Date().getTime() - new Date(app.updatedAt).getTime(),
|
|
||||||
})}
|
|
||||||
{:else}
|
|
||||||
Never updated
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div class="desktop">
|
|
||||||
<StatusLight
|
|
||||||
positive={!app.lockedYou && !app.lockedOther}
|
|
||||||
notice={app.lockedYou}
|
|
||||||
negative={app.lockedOther}
|
|
||||||
>
|
|
||||||
{#if app.lockedYou}
|
|
||||||
Locked by you
|
|
||||||
{:else if app.lockedOther}
|
|
||||||
Locked by {app.lockedBy.email}
|
|
||||||
{:else}
|
|
||||||
Open
|
|
||||||
{/if}
|
|
||||||
</StatusLight>
|
|
||||||
</div>
|
|
||||||
<div class="desktop">
|
|
||||||
<StatusLight active={app.deployed} neutral={!app.deployed}>
|
|
||||||
{#if app.deployed}Published{:else}Unpublished{/if}
|
|
||||||
</StatusLight>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
disabled={app.lockedOther}
|
disabled={app.lockedOther}
|
||||||
on:click={() => editApp(app)}
|
on:click={() => editApp(app)}
|
||||||
size="S"
|
size="S"
|
||||||
|
quiet
|
||||||
secondary>Open</Button
|
secondary>Open</Button
|
||||||
>
|
>
|
||||||
<ActionMenu align="right">
|
<ActionMenu align="right">
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
import {
|
import {
|
||||||
Heading,
|
Heading,
|
||||||
Layout,
|
Layout,
|
||||||
|
Detail,
|
||||||
Button,
|
Button,
|
||||||
ActionButton,
|
|
||||||
ActionGroup,
|
|
||||||
ButtonGroup,
|
ButtonGroup,
|
||||||
Input,
|
Input,
|
||||||
Select,
|
Select,
|
||||||
Modal,
|
Modal,
|
||||||
Page,
|
Page,
|
||||||
notifications,
|
notifications,
|
||||||
|
Body,
|
||||||
Search,
|
Search,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
|
@ -23,12 +23,10 @@
|
||||||
import download from "downloadjs"
|
import download from "downloadjs"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
import AppCard from "components/start/AppCard.svelte"
|
|
||||||
import AppRow from "components/start/AppRow.svelte"
|
import AppRow from "components/start/AppRow.svelte"
|
||||||
import { AppStatus } from "constants"
|
import { AppStatus } from "constants"
|
||||||
import analytics, { Events } from "analytics"
|
import analytics, { Events } from "analytics"
|
||||||
|
|
||||||
let layout = "grid"
|
|
||||||
let sortBy = "name"
|
let sortBy = "name"
|
||||||
let template
|
let template
|
||||||
let selectedApp
|
let selectedApp
|
||||||
|
@ -42,7 +40,7 @@
|
||||||
let cloud = $admin.cloud
|
let cloud = $admin.cloud
|
||||||
let appName = ""
|
let appName = ""
|
||||||
let creatingFromTemplate = false
|
let creatingFromTemplate = false
|
||||||
|
let templates = []
|
||||||
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
||||||
$: filteredApps = enrichedApps.filter(app =>
|
$: filteredApps = enrichedApps.filter(app =>
|
||||||
app?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
app?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
@ -260,8 +258,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchTemplates() {
|
||||||
|
const response = await api.get("/api/templates?type=app")
|
||||||
|
templates = await response.json()
|
||||||
|
console.log(templates)
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await apps.load()
|
await apps.load()
|
||||||
|
await fetchTemplates()
|
||||||
// if the portal is loaded from an external URL with a template param
|
// if the portal is loaded from an external URL with a template param
|
||||||
const initInfo = await auth.getInitInfo()
|
const initInfo = await auth.getInitInfo()
|
||||||
if (initInfo?.init_template) {
|
if (initInfo?.init_template) {
|
||||||
|
@ -274,17 +279,49 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Page wide>
|
<Page wide>
|
||||||
{#if loaded && enrichedApps.length}
|
<Layout gap="S" noPadding>
|
||||||
<Layout noPadding>
|
<div class="title">
|
||||||
|
<Heading size="S">Welcome to Budibase</Heading>
|
||||||
|
|
||||||
|
<ButtonGroup>
|
||||||
|
{#if cloud}
|
||||||
|
<Button secondary on:click={initiateAppsExport}>Export apps</Button>
|
||||||
|
{/if}
|
||||||
|
<Button secondary on:click={initiateAppImport}>Import app</Button>
|
||||||
|
<Button cta on:click={initiateAppCreation}>Create app</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
</div>
|
||||||
|
<Body size="XS">Manage your apps and get a head start with templates</Body>
|
||||||
|
|
||||||
|
<Detail>Quick Start Templates</Detail>
|
||||||
|
<div class="grid">
|
||||||
|
{#each templates as val}
|
||||||
|
<div class="template-card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div style="color: {val.background}" class="iconAlign">
|
||||||
|
<svg
|
||||||
|
width="26px"
|
||||||
|
height="26px"
|
||||||
|
class="spectrum-Icon"
|
||||||
|
style="color:{val.background};"
|
||||||
|
focusable="false"
|
||||||
|
>
|
||||||
|
<use xlink:href="#spectrum-icon-18-{val.icon}" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="iconAlign">
|
||||||
|
<Body weight="900" size="XS">{val.name}</Body>
|
||||||
|
<div style="font-size: 10px;">
|
||||||
|
<Body size="XS">{val.category.toUpperCase()}</Body>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{#if loaded && enrichedApps.length}
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<Heading>Apps</Heading>
|
<Detail>My Apps</Detail>
|
||||||
<ButtonGroup>
|
|
||||||
{#if cloud}
|
|
||||||
<Button secondary on:click={initiateAppsExport}>Export apps</Button>
|
|
||||||
{/if}
|
|
||||||
<Button secondary on:click={initiateAppImport}>Import app</Button>
|
|
||||||
<Button cta on:click={initiateAppCreation}>Create app</Button>
|
|
||||||
</ButtonGroup>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
<div class="select">
|
<div class="select">
|
||||||
|
@ -302,31 +339,14 @@
|
||||||
<Search placeholder="Search" bind:value={searchTerm} />
|
<Search placeholder="Search" bind:value={searchTerm} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<div class="mobile-search">
|
<div class="mobile-search">
|
||||||
<Search placeholder="Search" bind:value={searchTerm} />
|
<Search placeholder="Search" bind:value={searchTerm} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="appTable">
|
||||||
class:appGrid={layout === "grid"}
|
|
||||||
class:appTable={layout === "table"}
|
|
||||||
>
|
|
||||||
{#each filteredApps as app (app.appId)}
|
{#each filteredApps as app (app.appId)}
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={layout === "grid" ? AppCard : AppRow}
|
this={AppRow}
|
||||||
{releaseLock}
|
{releaseLock}
|
||||||
{app}
|
{app}
|
||||||
{unpublishApp}
|
{unpublishApp}
|
||||||
|
@ -338,21 +358,21 @@
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
{/if}
|
||||||
{/if}
|
{#if !enrichedApps.length && !creatingApp && loaded}
|
||||||
{#if !enrichedApps.length && !creatingApp && loaded}
|
<div class="empty-wrapper">
|
||||||
<div class="empty-wrapper">
|
<Modal inline>
|
||||||
<Modal inline>
|
<CreateAppModal {template} inline={true} />
|
||||||
<CreateAppModal {template} inline={true} />
|
</Modal>
|
||||||
</Modal>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
{#if creatingFromTemplate}
|
||||||
{#if creatingFromTemplate}
|
<div class="empty-wrapper">
|
||||||
<div class="empty-wrapper">
|
<p>Creating your Budibase app from your selected template...</p>
|
||||||
<p>Creating your Budibase app from your selected template...</p>
|
<Spinner size="10" />
|
||||||
<Spinner size="10" />
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</Layout>
|
||||||
</Page>
|
</Page>
|
||||||
<Modal
|
<Modal
|
||||||
bind:this={creationModal}
|
bind:this={creationModal}
|
||||||
|
@ -405,6 +425,36 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
.grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconAlign {
|
||||||
|
padding: 0 0 0 var(--spacing-m);
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.template-card {
|
||||||
|
height: 60px;
|
||||||
|
width: 255px;
|
||||||
|
border-radius: var(--border-radius-s);
|
||||||
|
margin-bottom: var(--spacing-m);
|
||||||
|
border: 1px solid var(--spectrum-global-color-gray-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 5px;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 200px) {
|
||||||
}
|
}
|
||||||
|
|
||||||
.select {
|
.select {
|
||||||
|
@ -419,11 +469,6 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.appGrid {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 50px;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
||||||
}
|
|
||||||
.appTable {
|
.appTable {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto;
|
grid-template-rows: auto;
|
||||||
|
|
Loading…
Reference in New Issue