Improve modal UI and discard changes (#5148)

* style(modal): Update header padding and add color to body

* style: Update font color in modal body paragraphs

* feat(ui): improve DemoModal structure and props usage

* style: Remove unnecessary global styles from Modal component

* feat(ui): Update DemoModal component onclick event and add onSubmit handler

* StoryBook: Update text in DemoModal

* add missing "submit"

* modal lint/checks fixes

* Update "Discard changes" modal
This commit is contained in:
Pavel Laptev 2024-10-15 16:25:02 +02:00 committed by GitHub
parent 436cd41f44
commit c6482a94de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 56 additions and 43 deletions

View File

@ -12,6 +12,7 @@
import { getContext } from '@gitbutler/shared/context';
import Button from '@gitbutler/ui/Button.svelte';
import Modal from '@gitbutler/ui/Modal.svelte';
import FileListItem from '@gitbutler/ui/file/FileListItem.svelte';
import { join } from '@tauri-apps/api/path';
export let branchId: string | undefined;
@ -116,19 +117,27 @@
<Modal
width="small"
type="warning"
title="Discard changes"
bind:this={confirmationModal}
onSubmit={confirmDiscard}
>
{#snippet children(item)}
<div>
Discarding changes to the following files:
{#if item.files.length < 10}
<p class="discard-caption">
Are you sure you want to discard the changes<br />to the following files:
</p>
<ul class="file-list">
{#each item.files as file}
<li><code class="code-string">{file.path}</code></li>
<FileListItem filePath={file.path} fileStatus={file.status} clickable={false} />
<!-- <li><code class="code-string">{file.path}</code></li> -->
{/each}
</ul>
</div>
{:else}
Discard the changes to all <span class="text-bold">
{item.files.length} files
</span>?
{/if}
{/snippet}
{#snippet controls(close, item)}
<Button style="ghost" outline onclick={close}>Cancel</Button>
@ -137,12 +146,14 @@
</Modal>
<style lang="postcss">
.file-list {
list-style: disc;
padding-left: 20px;
padding-top: 6px;
.discard-caption {
color: var(--clr-text-2);
}
.file-list li {
padding: 2px;
.file-list {
padding: 4px 0;
border-radius: var(--radius-m);
overflow: hidden;
border: 1px solid var(--clr-border-2);
margin-top: 12px;
}
</style>

View File

@ -62,7 +62,7 @@
<svelte:window on:keydown={handleKeyDown} />
<Modal bind:this={modal}>
<Modal bind:this={modal} onSubmit={submit}>
<h2 class="text-18 text-bold">Create an topic</h2>
<div class="input">
@ -93,7 +93,7 @@
{#snippet controls()}
<Button onclick={() => modal?.close()}>Cancel</Button>
<Button kind="solid" style="pop" onclick={submit} loading={submitProgress === 'loading'}
<Button kind="solid" style="pop" type="submit" loading={submitProgress === 'loading'}
>{topic ? 'Update' : 'Create'}</Button
>
{/snippet}

View File

@ -4,13 +4,12 @@
import { portal } from '$lib/utils/portal';
import { pxToRem } from '$lib/utils/pxToRem';
import { onDestroy } from 'svelte';
import type iconsJson from '$lib/data/icons.json';
import type { Snippet } from 'svelte';
interface Props {
width?: 'medium' | 'large' | 'small' | 'xsmall' | number;
type?: 'info' | 'warning' | 'error' | 'success';
title?: string;
icon?: keyof typeof iconsJson;
noPadding?: boolean;
onClose?: () => void;
onSubmit?: (close: () => void) => void;
@ -22,7 +21,7 @@
const {
width = 'medium',
title,
icon,
type = 'info',
onClose,
children,
controls,
@ -102,9 +101,18 @@
>
{#if title}
<div class="modal__header">
{#if icon}
<Icon name={icon} />
{#if type === 'warning'}
<Icon name="warning" color="warning" />
{/if}
{#if type === 'error'}
<Icon name="error" color="error" />
{/if}
{#if type === 'success'}
<Icon name="success" color="success" />
{/if}
<h2 class="text-14 text-semibold">
{title}
</h2>
@ -112,7 +120,9 @@
{/if}
<div class="modal__body custom-scrollbar text-13 text-body" class:no-padding={noPadding}>
{#if children}
{@render children(item, close)}
{/if}
</div>
{#if controls}
@ -171,9 +181,8 @@
.modal__header {
display: flex;
padding: 16px;
padding: 16px 16px 0;
gap: 8px;
border-bottom: 1px solid var(--clr-border-2);
}
.modal__body {
@ -186,8 +195,8 @@
}
}
.modal__body > :global(code),
.modal__body > :global(pre) {
.modal__body :global(code),
.modal__body :global(pre) {
word-wrap: break-word;
}

View File

@ -1,18 +1,10 @@
<script lang="ts">
import iconsJson from '$lib/data/icons.json';
import Button from '$lib/Button.svelte';
import Modal from '$lib/Modal.svelte';
import { type SvelteComponent } from 'svelte';
interface Props {
width?: 'small' | 'large' | 'medium' | 'xsmall' | number;
title?: string;
icon?: keyof typeof iconsJson;
}
const { ...args }: typeof Modal = $props();
const { ...args }: Props = $props();
let modal: SvelteComponent<Props>;
let modal: Modal;
</script>
<Button
@ -20,13 +12,14 @@
modal?.show();
}}>Show</Button
>
<Modal bind:this={modal} {...args}>
<p>Wonderful modal content</p>
<Modal bind:this={modal} {...args} onSubmit={() => console.log('submitted')}>
A branch with the same name already exists. Do you want to merge this branch into the current
branch?
{#snippet controls(close)}
<Button onclick={() => close()}>Close</Button>
<Button style="pop" kind="solid" type="submit" onclick={() => console.log('Submit clicked')}
>Submit</Button
<Button style="ghost" outline onclick={() => close()}>Cancel</Button>
<Button style="pop" kind="solid" type="submit" onclick={() => console.log('clicked')}
>Merge</Button
>
{/snippet}
</Modal>

View File

@ -1,22 +1,21 @@
import DemoModal from './DemoModal.svelte';
import iconsJson from '$lib/data/icons.json';
import type { Meta, StoryObj } from '@storybook/svelte';
import type { StoryObj } from '@storybook/svelte';
const meta = {
title: 'Overlays / Modal',
component: DemoModal,
component: DemoModal as any,
argTypes: {
width: {
control: 'select',
options: ['default', 'small', 'large']
},
title: { control: 'text' },
icon: {
type: {
control: 'select',
options: [undefined, ...Object.keys(iconsJson)]
options: ['info', 'success', 'warning', 'error']
}
}
} satisfies Meta<DemoModal>;
};
export default meta;
type Story = StoryObj<typeof meta>;
@ -25,6 +24,7 @@ export const DefaultStory: Story = {
name: 'Modal',
args: {
width: 'small',
type: 'info',
title: 'This is a fantastic modal :D'
}
};