mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
update: layout fixes
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import { IconViewBoards } from '@appwrite.io/pink-icons-svelte';
|
||||
import ViewToggle from './viewToggle.svelte';
|
||||
import ColumnSelector from './columnSelector.svelte';
|
||||
import { isSmallViewport } from '$lib/stores/viewport';
|
||||
|
||||
export let onlyIcon = false;
|
||||
export let ui: 'legacy' | 'new' = 'legacy';
|
||||
@@ -25,7 +26,7 @@
|
||||
size="s"
|
||||
icon={onlyIcon}
|
||||
variant="secondary"
|
||||
class={onlyIcon ? 'width-fix' : undefined}
|
||||
class={onlyIcon && !$isSmallViewport ? 'width-fix' : undefined}
|
||||
disabled={!$columns.length && showAnyway}
|
||||
badge={selectedColumnsNumber.toString()}
|
||||
on:click={toggle}>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
$isSmallViewport ? 'var(--font-size-m)' : 'var(--font-size-xxxl)'
|
||||
);
|
||||
|
||||
const currentFontSize = $derived(collapsed ? 'var(--font-size-l)' : expandedSize);
|
||||
// const currentFontSize = $derived(collapsed ? 'var(--font-size-l)' : 'var(--font-size-xxxl)');
|
||||
// const currentFontSize = $derived(collapsed ? 'var(--font-size-l)' : expandedSize);
|
||||
const currentFontSize = $derived(collapsed ? 'var(--font-size-l)' : 'var(--font-size-xxxl)');
|
||||
|
||||
const currentLineHeight = $derived(collapsed ? '130%' : '140%');
|
||||
const currentLetterSpacing = $derived(collapsed ? '0' : '-0.144px');
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
// TODO: needs better props
|
||||
|
||||
export let expanded = false;
|
||||
export let expandHeightButton = false;
|
||||
export let slotSpacing = false;
|
||||
export let overlapCover = false;
|
||||
export let paddingInlineEnd = true;
|
||||
export let databasesScreen = false;
|
||||
export let expandHeightButton = false;
|
||||
export let size: 'small' | 'medium' | 'large' | 'xl' | 'xxl' | 'xxxl' = null;
|
||||
|
||||
$: style = size
|
||||
@@ -45,6 +45,11 @@
|
||||
padding-inline-end: 0 !important;
|
||||
margin-block: var(--base-8) !important;
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
margin-inline: 0 !important;
|
||||
padding-inline: 53px !important;
|
||||
}
|
||||
|
||||
&.expandHeightButton {
|
||||
margin-inline-end: unset;
|
||||
margin-inline-start: 2.75rem;
|
||||
@@ -81,25 +86,34 @@
|
||||
&.databasesScreen {
|
||||
@media (min-width: 1440px) {
|
||||
min-width: 1070px;
|
||||
max-width: 1144px;
|
||||
/*max-width: 1144px;*/
|
||||
}
|
||||
|
||||
@media (min-width: 1728px) {
|
||||
min-width: 1070px;
|
||||
padding-inline: 196px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 360px) {
|
||||
margin-inline: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
margin-inline: auto;
|
||||
max-width: calc(944px - 11rem);
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
margin-inline: auto;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
margin-inline: auto;
|
||||
max-width: 1144px;
|
||||
}
|
||||
|
||||
@media (min-width: 1728px) {
|
||||
margin-inline: auto;
|
||||
max-width: 1200px;
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class:animate
|
||||
class:expanded
|
||||
class:collapsed={animate && collapsed}
|
||||
class:animate
|
||||
class="top-cover-console"
|
||||
style:block-size={animatedBlocksize}
|
||||
style:margin-top={marginTop}
|
||||
style:block-size={animatedBlocksize}
|
||||
style:padding-block-start={headerPaddingTop}
|
||||
style:padding-block-end={headerPaddingBottom}>
|
||||
<div
|
||||
@@ -91,18 +91,22 @@
|
||||
@media (min-width: 360px) {
|
||||
margin-inline: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
margin-inline: auto;
|
||||
max-width: calc(944px - 11rem);
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
margin-inline: auto;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
margin-inline: auto;
|
||||
max-width: 1144px;
|
||||
}
|
||||
|
||||
@media (min-width: 1728px) {
|
||||
margin-inline: auto;
|
||||
max-width: 1200px;
|
||||
@@ -119,5 +123,8 @@
|
||||
|
||||
.expanded-slot {
|
||||
margin-inline: 3rem !important;
|
||||
@media (max-width: 768px) {
|
||||
margin-inline: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
// for spreadsheet ui
|
||||
const hideFooter = $derived(page.route.id?.includes('table-[table]'));
|
||||
const hideFooter = $derived.by(() => {
|
||||
const endings = ['table-[table]', 'table-[table]/columns', 'table-[table]/indexes'];
|
||||
return endings.some((end) => page.route.id?.endsWith(end));
|
||||
});
|
||||
</script>
|
||||
|
||||
<footer class:hide={hideFooter}>
|
||||
@@ -175,10 +177,15 @@
|
||||
|
||||
:global(main:has(.sub-navigation)) footer {
|
||||
@media (min-width: 1024px) {
|
||||
margin-inline-start: -1.5rem;
|
||||
margin-inline-end: 2rem;
|
||||
margin-inline-start: -1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
:global(main:has(.wide-screen-wrapper)) footer {
|
||||
margin-inline-start: 2rem !important;
|
||||
}
|
||||
|
||||
.extra-margin {
|
||||
margin-block-start: var(--space-2, 4px);
|
||||
}
|
||||
|
||||
@@ -239,21 +239,13 @@
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.main-content {
|
||||
.main-content:not(:has(.wide-screen-wrapper)) {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(main:has(.wide-screen-wrapper)) {
|
||||
@media (min-width: 1728px) {
|
||||
.main-content {
|
||||
padding-left: 255px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
|
||||
+83
-88
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Container } from '$lib/layout';
|
||||
import {
|
||||
ActionMenu,
|
||||
Badge,
|
||||
@@ -117,6 +116,17 @@
|
||||
enum: IconViewList
|
||||
};
|
||||
|
||||
const emptyCellsLimit = $derived($isSmallViewport ? 16 : 18);
|
||||
const emptyCellsCount = $derived(
|
||||
updatedColumnsForSheet.length >= emptyCellsLimit
|
||||
? 0
|
||||
: emptyCellsLimit - updatedColumnsForSheet.length
|
||||
);
|
||||
|
||||
onMount(() => {
|
||||
columnsOrder = preferences.getColumnOrder(tableId);
|
||||
});
|
||||
|
||||
function getColumnStatusBadge(status: string): ComponentProps<Badge>['type'] {
|
||||
switch (status) {
|
||||
case 'processing':
|
||||
@@ -130,16 +140,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
const emptyCellsLimit = $derived($isSmallViewport ? 14 : 17);
|
||||
const emptyCellsCount = $derived(
|
||||
updatedColumnsForSheet.length >= emptyCellsLimit
|
||||
? 0
|
||||
: emptyCellsLimit - updatedColumnsForSheet.length
|
||||
);
|
||||
|
||||
onMount(() => {
|
||||
columnsOrder = preferences.getColumnOrder(tableId);
|
||||
});
|
||||
function getMinMaxSizeForColumn(column: Columns): string | undefined {
|
||||
if (column.type === 'string' && !column['format'] && column.key !== '$id') {
|
||||
const stringColumn = column as Models.ColumnString;
|
||||
return `Size: ${stringColumn.size}`;
|
||||
} else if (column.type === 'integer' || column.type === 'double') {
|
||||
const numbersColumn = column as Models.ColumnInteger | Models.ColumnFloat;
|
||||
return `Min: ${numbersColumn.min}, Max: ${numbersColumn.max}`;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => ($showCreateAttributeSheet.show = false));
|
||||
|
||||
@@ -151,22 +162,6 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<Container expanded style="background: var(--bgcolor-neutral-primary)">
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
{#if updatedColumnsForSheet}
|
||||
<Button
|
||||
size="s"
|
||||
secondary
|
||||
disabled={$isCsvImportInProgress}
|
||||
on:click={() => ($showCreateAttributeSheet.show = true)}
|
||||
event="create_attribute">
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Create column
|
||||
</Button>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Container>
|
||||
|
||||
<div class="databases-spreadsheet">
|
||||
<SpreadsheetContainer bind:this={spreadsheetContainer}>
|
||||
<Spreadsheet.Root
|
||||
@@ -176,8 +171,8 @@
|
||||
emptyCells={emptyCellsCount}
|
||||
bind:selectedRows={selectedColumns}
|
||||
columns={[
|
||||
{ id: 'key', width: { min: 200 } },
|
||||
{ id: 'size', width: { min: 200 } },
|
||||
// more size until we decide if we want a new column!
|
||||
{ id: 'key', width: { min: $isSmallViewport ? 250 : 200 } },
|
||||
{ id: 'indexed', width: { min: 150 } },
|
||||
{ id: 'default', width: { min: 200 } },
|
||||
{ id: 'actions', width: 40, isAction: true }
|
||||
@@ -185,7 +180,6 @@
|
||||
bottomActionClick={() => ($showCreateAttributeSheet.show = true)}>
|
||||
<svelte:fragment slot="header" let:root>
|
||||
<Spreadsheet.Header.Cell column="key" {root}>Column name</Spreadsheet.Header.Cell>
|
||||
<Spreadsheet.Header.Cell column="size" {root}>Size</Spreadsheet.Header.Cell>
|
||||
<Spreadsheet.Header.Cell column="indexed" {root}>Indexed</Spreadsheet.Header.Cell>
|
||||
<Spreadsheet.Header.Cell column="default" {root}
|
||||
>Default value</Spreadsheet.Header.Cell>
|
||||
@@ -199,71 +193,72 @@
|
||||
column['system'] || column.type === 'relationship' ? 'disabled' : true}
|
||||
<Spreadsheet.Row.Base {root} select={isSelectable} id={column.key}>
|
||||
<Spreadsheet.Cell column="key" {root} isEditable={false}>
|
||||
<Layout.Stack direction="row" alignItems="center">
|
||||
{#if isRelationship(column)}
|
||||
<Icon
|
||||
size="s"
|
||||
icon={column?.twoWay
|
||||
? IconSwitchHorizontal
|
||||
: IconArrowSmRight} />
|
||||
{:else if 'format' in column && column.format}
|
||||
{@const icon = columnFormatIcon[column?.format]}
|
||||
<Icon {icon} size="s" />
|
||||
{:else if column.key === '$id'}
|
||||
<Icon icon={IconFingerPrint} size="s" />
|
||||
{:else}
|
||||
<Icon icon={option.icon} size="s" />
|
||||
{/if}
|
||||
<Layout.Stack direction="row" justifyContent="space-between">
|
||||
<Layout.Stack direction="row" alignItems="center" inline>
|
||||
{#if isRelationship(column)}
|
||||
<Icon
|
||||
size="s"
|
||||
icon={column?.twoWay
|
||||
? IconSwitchHorizontal
|
||||
: IconArrowSmRight} />
|
||||
{:else if 'format' in column && column.format}
|
||||
{@const icon = columnFormatIcon[column?.format]}
|
||||
<Icon {icon} size="s" />
|
||||
{:else if column.key === '$id'}
|
||||
<Icon icon={IconFingerPrint} size="s" />
|
||||
{:else}
|
||||
<Icon icon={option.icon} size="s" />
|
||||
{/if}
|
||||
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Layout.Stack inline direction="row" alignItems="center" gap="xxs">
|
||||
<span class="text u-trim-1" data-private>
|
||||
{#if column.key === '$id' || column.key === '$sequence' || column.key === '$createdAt' || column.key === '$updatedAt'}
|
||||
{column['name']}
|
||||
{:else}
|
||||
{column.key} {column.array ? '[]' : undefined}
|
||||
<Layout.Stack direction="row" alignItems="center" gap="s">
|
||||
<Layout.Stack
|
||||
inline
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap="xxs">
|
||||
<span class="text u-trim-1" data-private>
|
||||
{#if column.key === '$id' || column.key === '$sequence' || column.key === '$createdAt' || column.key === '$updatedAt'}
|
||||
{column['name']}
|
||||
{:else}
|
||||
{column.key} {column.array ? '[]' : undefined}
|
||||
{/if}
|
||||
</span>
|
||||
{#if isString(column) && column.encrypt}
|
||||
<Tooltip>
|
||||
<Icon
|
||||
size="s"
|
||||
icon={IconLockClosed}
|
||||
color="--fgcolor-neutral-tertiary" />
|
||||
<div slot="tooltip">Encrypted</div>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</span>
|
||||
{#if isString(column) && column.encrypt}
|
||||
<Tooltip>
|
||||
<Icon
|
||||
size="s"
|
||||
icon={IconLockClosed}
|
||||
color="--fgcolor-neutral-tertiary" />
|
||||
<div slot="tooltip">Encrypted</div>
|
||||
</Tooltip>
|
||||
</Layout.Stack>
|
||||
{#if column.status !== 'available'}
|
||||
<Badge
|
||||
size="s"
|
||||
variant="secondary"
|
||||
content={column.status}
|
||||
type={getColumnStatusBadge(column.status)} />
|
||||
{#if column.error}
|
||||
<Link.Button
|
||||
variant="muted"
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
error = column.error;
|
||||
showFailed = true;
|
||||
}}>Details</Link.Button>
|
||||
{/if}
|
||||
{:else if column.required}
|
||||
<Badge size="xs" variant="secondary" content="required" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{#if column.status !== 'available'}
|
||||
<Badge
|
||||
size="s"
|
||||
variant="secondary"
|
||||
content={column.status}
|
||||
type={getColumnStatusBadge(column.status)} />
|
||||
{#if column.error}
|
||||
<Link.Button
|
||||
variant="muted"
|
||||
on:click={(e) => {
|
||||
e.preventDefault();
|
||||
error = column.error;
|
||||
showFailed = true;
|
||||
}}>Details</Link.Button>
|
||||
{/if}
|
||||
{:else if column.required}
|
||||
<Badge size="xs" variant="secondary" content="required" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
{@const minMaxSize = getMinMaxSizeForColumn(column)}
|
||||
{#if minMaxSize}
|
||||
<Badge size="xs" content={minMaxSize} variant="secondary" />
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Spreadsheet.Cell>
|
||||
<Spreadsheet.Cell column="size" {root} isEditable={false}>
|
||||
{#if column.type === 'string'}
|
||||
{column.size /* or length */}
|
||||
{:else if column.type === 'integer' || column.type === 'double'}
|
||||
Min: {column.min} Max: {column.max}
|
||||
{:else}
|
||||
-
|
||||
{/if}
|
||||
</Spreadsheet.Cell>
|
||||
<Spreadsheet.Cell column="indexed" {root} isEditable={false}>
|
||||
{@const isIndexed = $indexes.some((index) =>
|
||||
index.columns.includes(column.key)
|
||||
|
||||
+43
-25
@@ -59,37 +59,55 @@
|
||||
const link = $derived(
|
||||
`${base}/project-${page.params.region}-${page.params.project}/databases/database-${databaseId}`
|
||||
);
|
||||
|
||||
const nonSheetPages = $derived.by(() => {
|
||||
const endings = ['table-[table]', 'table-[table]/columns', 'table-[table]/indexes'];
|
||||
const isSpreadsheetPage = endings.some((end) => page.route.id?.endsWith(end));
|
||||
return !isSpreadsheetPage;
|
||||
});
|
||||
</script>
|
||||
|
||||
<Cover expanded collapsed={!$expandTabs} blocksize={$expandTabs ? '152px' : '90px'} animate={true}>
|
||||
<svelte:fragment slot="header">
|
||||
<Layout.Stack direction="row" alignContent="center" alignItems="center" inline>
|
||||
<AnimatedTitle href={link} collapsed={!$expandTabs}>
|
||||
{$table?.name}
|
||||
</AnimatedTitle>
|
||||
<div class:nonSheetPages>
|
||||
<Cover animate expanded collapsed={!$expandTabs} blocksize={$expandTabs ? '152px' : '90px'}>
|
||||
<svelte:fragment slot="header">
|
||||
<Layout.Stack direction="row" alignContent="center" alignItems="center" inline>
|
||||
<AnimatedTitle href={link} collapsed={!$expandTabs}>
|
||||
{$table?.name}
|
||||
</AnimatedTitle>
|
||||
|
||||
{#key $table?.$id}
|
||||
<Id value={$table?.$id} tooltipPlacement={$expandTabs ? undefined : 'right'}
|
||||
>{$table?.$id}</Id>
|
||||
{/key}
|
||||
</Layout.Stack>
|
||||
</svelte:fragment>
|
||||
{#key $table?.$id}
|
||||
<Id value={$table?.$id} tooltipPlacement={$expandTabs ? undefined : 'right'}
|
||||
>{$table?.$id}</Id>
|
||||
{/key}
|
||||
</Layout.Stack>
|
||||
</svelte:fragment>
|
||||
|
||||
<div class="tabs-container" class:collapsed={!$expandTabs}>
|
||||
<Tabs>
|
||||
{#each tabs as tab}
|
||||
<Tab
|
||||
href={tab.href}
|
||||
selected={isTabSelected(tab, page.url.pathname, path, tabs)}
|
||||
event={tab.event}>
|
||||
{tab.title}
|
||||
</Tab>
|
||||
{/each}
|
||||
</Tabs>
|
||||
</div>
|
||||
</Cover>
|
||||
<div class="tabs-container" class:collapsed={!$expandTabs}>
|
||||
<Tabs>
|
||||
{#each tabs as tab}
|
||||
<Tab
|
||||
href={tab.href}
|
||||
selected={isTabSelected(tab, page.url.pathname, path, tabs)}
|
||||
event={tab.event}>
|
||||
{tab.title}
|
||||
</Tab>
|
||||
{/each}
|
||||
</Tabs>
|
||||
</div>
|
||||
</Cover>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.nonSheetPages :global(.cover-container) {
|
||||
@media (min-width: 1440px) {
|
||||
padding-inline: 7px !important;
|
||||
}
|
||||
|
||||
@media (min-width: 1728px) {
|
||||
padding-inline: 10.25rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
opacity: 1;
|
||||
transition: opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
-15
@@ -94,21 +94,6 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<Container expanded style="background: var(--bgcolor-neutral-primary)">
|
||||
<Layout.Stack direction="row" justifyContent="flex-end">
|
||||
{#if $canWriteTables}
|
||||
<Button
|
||||
secondary
|
||||
event="create_index"
|
||||
disabled={!$table?.columns?.length}
|
||||
on:click={() => (showCreateIndex = true)}>
|
||||
<Icon icon={IconPlus} slot="start" size="s" />
|
||||
Create index
|
||||
</Button>
|
||||
{/if}
|
||||
</Layout.Stack>
|
||||
</Container>
|
||||
|
||||
<div class="databases-spreadsheet">
|
||||
{#if data.table?.columns?.length}
|
||||
{#if data.table.indexes.length}
|
||||
|
||||
+6
-2
@@ -310,8 +310,12 @@
|
||||
height: 79.1vh !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
height: 70vh;
|
||||
@media (max-width: 1024px) {
|
||||
height: 76vh;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
height: 80.35vh;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
import UpdateStatus from './updateStatus.svelte';
|
||||
</script>
|
||||
|
||||
<div class="wide-screen-wrapper databases-spreadsheet">
|
||||
<div class="wide-screen-wrapper databases-spreadsheet" style:padding-bottom="1rem">
|
||||
<Container expanded slotSpacing databasesScreen>
|
||||
{#if $table}
|
||||
<UpdateStatus />
|
||||
|
||||
+2
-1
@@ -76,6 +76,7 @@
|
||||
import { pageToOffset } from '$lib/helpers/load';
|
||||
import { debounce } from '$lib/helpers/debounce';
|
||||
import { hash } from '$lib/helpers/string';
|
||||
import { abbreviateNumber } from '$lib/helpers/numbers';
|
||||
|
||||
export let data: PageData;
|
||||
export let showRecordsCreateSheet: {
|
||||
@@ -905,7 +906,7 @@
|
||||
<span style:white-space="nowrap">
|
||||
{selectedRows.length
|
||||
? `${selectedRows.length} row${selectedRows.length === 1 ? '' : 's'} selected`
|
||||
: `${$rows.total} row${$rows.total === 1 ? '' : 's'}`}
|
||||
: `${abbreviateNumber($rows.total)} row${$rows.total === 1 ? '' : 's'}`}
|
||||
</span>
|
||||
</Typography.Text>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user