Merge branch 'mgn-dv' of https://github.com/appwrite/console into mgn-dv

This commit is contained in:
Torsten Dittmann
2025-05-07 17:15:31 +02:00
9 changed files with 106 additions and 178 deletions
-111
View File
@@ -78,13 +78,9 @@
) as Artifact[];
$: selectedOrg = organizations.find((organization) => organization.isSelected);
$: selectedProject = selectedOrg?.projects.find((project) => project.isSelected);
$: selectedArtifact = displayArtifacts.find(
(artifact) => $page.params.artifact === artifact.$id
) as Artifact;
let organisationBottomSheetOpen = false;
let projectsBottomSheetOpen = false;
let artifactsBottomSheetOpen = false;
function createOrg() {
trackEvent(Click.OrganizationClickCreate, { source: 'breadcrumbs' });
@@ -192,54 +188,6 @@
: undefined
};
let artifactsBottomSheet: SheetMenu;
$: artifactsBottomSheet = {
top:
displayArtifacts.length > 1
? {
title: 'Switch artifact',
items: !selectedOrg
? []
: displayArtifacts
.map((artifact, index) => {
if (index < 4) {
return {
name: artifact.name,
href: `${base}/project-${selectedProject.$id}/studio/artifact-${artifact.$id}`
};
} else if (index === 4) {
return {
name: 'All artifacts',
href: `${base}/project-${selectedProject.$id}/studio`
};
}
return null;
})
.filter((project) => project !== null)
}
: {
items: [
{
name: 'Create project',
trailingIcon: IconPlus,
href: `${base}/organization-${selectedOrg?.$id}?create-project`
}
]
},
bottom:
selectedOrg?.projects.length > 1
? {
items: [
{
name: 'Create project',
trailingIcon: IconPlus,
href: `${base}/organization-${selectedOrg?.$id}?create-project`
}
]
}
: undefined
};
function onResize() {
if ((organisationBottomSheetOpen || projectsBottomSheetOpen) && !$isSmallViewport) {
organisationBottomSheetOpen = false;
@@ -410,70 +358,11 @@
</Card.Base>
</div>
{/if}
{#if isStudio && displayArtifacts.length > 0 && selectedProject}
<span class="breadcrumb-separator">/</span>
{#if !$isSmallViewport}
<button
type="button"
class="trigger"
use:melt={$triggerArtifacts}
aria-label="Open artifacts tab">
<span class="projectName">{selectedArtifact?.name}</span>
<Icon icon={IconChevronDown} size="s" />
</button>
{:else}
<button
type="button"
class="trigger"
on:click={() => (artifactsBottomSheetOpen = true)}
aria-label="Open artifacts tab">
<span class="projectName">{selectedArtifact.name}</span>
<Icon icon={IconChevronDown} size="s" />
</button>
{/if}
<div class="menu" use:melt={$menuArtifacts}>
<Card.Base padding="xxxs" shadow={true}>
{#if displayArtifacts.length > 1}
{#each displayArtifacts as artifact, index}
{#if index < 4}
<div use:melt={$itemArtifacts}>
<ActionMenu.Root>
<ActionMenu.Item.Anchor
href={`${base}/project-${selectedProject.$id}/studio/artifact-${artifact.$id}`}
>{artifact.name}</ActionMenu.Item.Anchor
></ActionMenu.Root>
</div>
{:else if index === 4}
<div use:melt={$itemArtifacts}>
<ActionMenu.Root>
<ActionMenu.Item.Anchor
href={`${base}/project-${selectedProject.$id}/studio`}
>All artifacts</ActionMenu.Item.Anchor
></ActionMenu.Root>
</div>
{/if}
{/each}
<div class="separator" use:melt={$separatorArtifacts}></div>
{/if}
<div use:melt={$itemArtifacts}>
<ActionMenu.Root>
<ActionMenu.Item.Anchor
leadingIcon={IconPlusSm}
href={`${base}/project-${selectedProject.$id}/studio?create-project`}
>Create artifact</ActionMenu.Item.Anchor
></ActionMenu.Root>
</div>
</Card.Base>
</div>
{/if}
</div>
<BottomSheet.Menu bind:isOpen={organisationBottomSheetOpen} menu={organizationsBottomSheet}
></BottomSheet.Menu>
<BottomSheet.Menu bind:isOpen={projectsBottomSheetOpen} menu={projectsBottomSheet}
></BottomSheet.Menu>
<BottomSheet.Menu bind:isOpen={artifactsBottomSheetOpen} menu={artifactsBottomSheet}
></BottomSheet.Menu>
<style lang="scss">
.menu {
+17 -5
View File
@@ -4,7 +4,7 @@
IconArrowUp,
IconChevronDown,
IconChevronLeft,
IconPaperClip,
IconPaperClip
} from '@appwrite.io/pink-icons-svelte';
import { isSmallViewport } from '$lib/stores/viewport';
import Conversation from './conversation.svelte';
@@ -111,7 +111,9 @@
color="--fgcolor-neutral-tertiary" /></Button.Button>
</Layout.Stack>
</header>
<Divider />
<div class="divider-wrapper">
<Divider />
</div>
<Conversation {parser} />
{/if}
@@ -206,20 +208,29 @@
'.'
'.';
height: calc(100% - var(--space-4));
background-color: var(--bgcolor-neutral-primary);
width: 100%;
background-color: var(--bgcolor-neutral-primary);
border: 1px solid var(--border-neutral);
border-radius: var(--border-radius-m);
@media (min-width: 768px) {
height: 100%;
background-color: transparent;
border: 0;
border-radius: 0;
}
}
header {
display: grid;
gap: 1rem;
padding: 1rem;
padding: var(--base-8);
}
.divider-wrapper {
margin-inline-start: calc(-1 * var(--base-24));
width: calc(100% + 30px);
}
.is-visible .chat-content {
@@ -228,8 +239,9 @@
}
.input {
border-top: 1px solid var(--border-neutral);
border: 1px solid var(--border-neutral);
border-radius: var(--border-radius-m);
margin-block-end: var(--space-4);
padding: var(--space-6);
textarea {
@@ -13,7 +13,6 @@
import { base } from '$app/paths';
import { isSmallViewport, isTabletViewport } from '$lib/stores/viewport';
import type { ComponentType } from 'svelte';
import { showChat } from '$lib/stores/chat';
import { page } from '$app/state';
export let project;
@@ -57,17 +56,6 @@
{/if}
{/each}
</Layout.Stack>
{#if !$isSmallViewport}
<ActionMenu.Item.Button
on:click={() => {
showChat.set(!$showChat);
if ($isTabletViewport) {
isOpen = false;
}
}}>
<Icon icon={IconSparkles} />
</ActionMenu.Item.Button>
{/if}
</Layout.Stack>
</nav>
+1 -1
View File
@@ -37,7 +37,7 @@
const { data } = message;
term.write(data);
});
const observer = new ResizeObserver(([entry]) => {
const observer = new ResizeObserver(() => {
const { cols, rows } = fitAddon.proposeDimensions();
if (term.cols === cols && term.rows === rows) return;
term.resize(cols, rows);
-1
View File
@@ -23,7 +23,6 @@ export function getChatWidthFromPrefs(): number {
}
export function saveChatWidthToPrefs(position: number) {
const currentPrefs = userPreferences();
const newPrefs = {
...currentPrefs,
studioChatWidth: position
+42 -28
View File
@@ -113,7 +113,7 @@
let resizerLeftPosition = $state(
page.data?.subNavigation ? getChatWidthFromPrefs() + 24 : getChatWidthFromPrefs()
);
let resizerLeftOffset = $state(page.data?.subNavigation ? 52 : 52);
let resizerLeftOffset = $state(page.data?.subNavigation ? 52 : 60);
let chatWidth = $derived(resizerLeftPosition - resizerLeftOffset);
$effect(() => {
@@ -145,18 +145,27 @@
: window.innerWidth - 460;
const minSize = 320;
if (resizerLeftPosition > maxSize) {
resizerLeftPosition = maxSize;
} else if (resizerLeftPosition < minSize) {
if (resizerLeftPosition < minSize - 100) {
showChat.set(false);
}
resizerLeftPosition = minSize;
} else if (resizerLeftPosition > minSize && !$showChat) {
showChat.set(true);
}
}
}
function stopResize() {
if (!$showChat) {
resizerLeftPosition = 500;
}
const saveWidth = page.data?.subNavigation ? resizerLeftPosition - 24 : resizerLeftPosition;
saveChatWidthToPrefs(saveWidth);
isResizing = false;
window.removeEventListener('mousemove', resize);
window.removeEventListener('mouseup', stopResize);
@@ -336,22 +345,23 @@
</Layout.Stack>
</Card.Base>
{:else}
<Layout.Stack direction="row" gap="l">
{#if hasProjectSidebar}
<Chat {parser} width={chatWidth} hasSubNavigation={false} />
{#if $showChat}
<div
role="presentation"
class="resizer"
style:left={`${resizerLeftPosition}px`}
bind:this={resizer}
onmousedown={startResize}
ontouchmove={startResize}>
</div>
<Card.Base padding="xxs">
<Layout.Stack direction="row" gap={$showChat ? 'l' : 'none'}>
{#if hasProjectSidebar}
<Chat {parser} width={chatWidth} hasSubNavigation={false} />
{#if $showChat || isResizing}
<div
role="presentation"
class="resizer"
style:left={`${resizerLeftPosition}px`}
class:hidden={!$showChat}
bind:this={resizer}
onmousedown={startResize}
ontouchmove={startResize}>
</div>
{/if}
{/if}
{/if}
<Card.Base>
{@const Header = page.data.header}
{#if page.data.subNavigation}
{@const SubNavigation = page.data.subNavigation}
@@ -372,8 +382,8 @@
{@render children()}
</Layout.Stack>
{/if}
</Card.Base>
</Layout.Stack>
</Layout.Stack>
</Card.Base>
{/if}
</div>
{#if hasProjectSidebar}
@@ -472,7 +482,7 @@
.studio-content {
min-height: calc(100vh - 54px);
margin-top: 54px;
margin-top: 32px;
width: 100vw;
padding-right: var(--space-4);
@@ -481,6 +491,7 @@
@media (min-width: 1024px) {
width: calc(100vw - 200px);
margin-left: 200px;
margin-top: 54px;
padding-left: 0;
}
@@ -497,28 +508,31 @@
cursor: col-resize;
margin-inline: 10px;
position: absolute;
height: calc(100vh - 82px);
margin-block-start: 6px;
margin-inline-start: 0px;
height: calc(100vh - 72px);
margin-block-start: calc(-1 * var(--base-8));
margin-inline-start: 0;
&::after {
content: '';
cursor: col-resize;
position: absolute;
height: 100%;
width: 2px;
width: 1px;
margin-left: -1px;
left: 8px;
background-color: var(--border-neutral-strong);
opacity: 0;
transition: opacity 0.3s ease-in-out;
background-color: var(--border-neutral);
opacity: 1;
transition: all 0.3s ease-in-out;
}
&:hover::after {
opacity: 1;
width: 2px;
background-color: var(--border-neutral-strong);
}
}
.hidden {
opacity: 0;
}
@media (min-width: 1024px) {
.only-mobile-tablet {
@@ -1,5 +1,5 @@
<script lang="ts">
import { Layout, Typography, Divider, Icon } from '@appwrite.io/pink-svelte';
import { Layout, Typography, Divider, Icon, Button } from '@appwrite.io/pink-svelte';
import { isTabSelected } from '$lib/helpers/load';
import { page } from '$app/state';
import { Tab, Tabs, Terminal } from '$lib/components';
@@ -15,6 +15,8 @@
saveTerminalOpenToPrefs
} from '$lib/helpers/studioLayout';
import { synapse } from '$lib/components/studio/synapse.svelte';
import { showChat } from '$lib/stores/chat';
import { default as IconChatLayout } from '../assets/chat-layout.svelte';
const { children } = $props();
@@ -91,20 +93,32 @@
<Layout.Stack
direction="column"
height={$isSmallViewport ? 'calc(100vh - 218px)' : 'calc(100vh - 120px)'}
height={$isSmallViewport ? 'calc(100vh - 218px)' : 'calc(100vh - 88px)'}
gap="none">
<Layout.Stack direction="column">
<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>
<Divider />
<Layout.Stack direction="column" gap="none">
<Layout.Stack gap="xxs" direction="row" alignItems="center">
{#if !$showChat}
<Button.Button
variant="compact"
color="--fgcolor-neutral-secondary"
on:click={() => {
showChat.set(true);
}}><Icon icon={IconChatLayout} size="l"></Icon></Button.Button>
{/if}
<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>
</Layout.Stack>
<div class="divider-wrapper">
<Divider />
</div>
</Layout.Stack>
{@render children()}
<aside bind:this={asideRef}>
@@ -131,9 +145,8 @@
background-color: var(--bgcolor-neutral-default);
margin-inline-start: -25px;
margin-block-end: calc(-1 * var(--space-9));
margin-block-end: calc(-1 * var(--base-8));
padding: var(--space-3);
border-bottom-left-radius: var(--border-radius-m);
border-bottom-right-radius: var(--border-radius-m);
border: 1px solid var(--border-neutral);
@@ -143,8 +156,8 @@
bottom: 116px;
@media (min-width: 768px) {
width: calc(100% + 2 * var(--space-9));
margin-inline-start: calc(-1 * var(--space-9));
width: calc(100% + var(--base-16));
margin-inline-start: calc(-1 * var(--space-4));
position: static;
border: 0;
}
@@ -156,4 +169,11 @@
.terminal-slider {
cursor: row-resize;
}
.divider-wrapper {
margin-block-start: 7.5px;
margin-inline-start: -9px;
margin-block-end: 8px;
width: calc(100% + 18px);
}
</style>
@@ -37,8 +37,8 @@
}
iframe {
border: none;
width: calc(100% + 2 * var(--space-9));
width: calc(100% + 2 * var(--base-8));
height: 100%;
margin-inline-start: calc(-1 * var(--space-9));
margin-inline-start: calc(-1 * var(--base-8));
}
</style>
@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M6.00488 16.2957C6.05278 16.7348 6.42703 17.0841 6.89746 17.1288L7 17.1333H17L17.1025 17.1288C17.573 17.0841 17.9472 16.7348 17.9951 16.2957L18 16.2V7.8C18 7.31683 17.6067 6.91913 17.1025 6.87122L17 6.86667V5C18.6569 5 20 6.2536 20 7.8V16.2C20 17.7464 18.6569 19 17 19H7C5.34315 19 4 17.7464 4 16.2V7.8C4 6.2536 5.34315 5 7 5V6.86667L6.89746 6.87122C6.39333 6.91913 6 7.31684 6 7.8V16.2L6.00488 16.2957ZM17 5V6.86667H7V5H17Z"
fill="currentcolor" />
<path d="M11 6V18H9V6H11Z" fill="currentcolor" />
</svg>

After

Width:  |  Height:  |  Size: 635 B