Skip to content

Commit 198c277

Browse files
committed
add import dialog
1 parent ad6ee9e commit 198c277

File tree

11 files changed

+198
-21
lines changed

11 files changed

+198
-21
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
"devDependencies": {
1616
"@sveltejs/vite-plugin-svelte": "^3.0.1",
1717
"@tsconfig/svelte": "^5.0.2",
18-
"@types/yargs-parser": "^21",
18+
"@types/yargs-parser": "^21.0.3",
1919
"@typescript-eslint/eslint-plugin": "^6.17.0",
2020
"@typescript-eslint/parser": "^6.17.0",
21+
"@zerodevx/svelte-toast": "^0.9.5",
2122
"eslint": "^8.56.0",
2223
"eslint-config-prettier": "^9.1.0",
2324
"eslint-plugin-svelte": "^2.35.1",

src/components/ExportOptions.svelte

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,6 @@
9191
h3 {
9292
margin: 0;
9393
}
94-
.export {
95-
position: absolute;
96-
top: 15px;
97-
right: 15px;
98-
}
9994
10095
.content {
10196
display: flex;

src/components/Home.svelte

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
import { importFromUrlHash } from '~/data/import/importFromUrlHash';
1111
import { colorsStore } from '~/data/colors.store';
1212
import { optionsStore } from '~/data/options.store';
13+
import ExportOptions from '~/components/ExportOptions.svelte';
14+
import ImportOptions from '~/components/ImportOptions.svelte';
15+
import { SvelteToast } from '@zerodevx/svelte-toast';
1316
1417
let terminalContentEl: HTMLDivElement;
1518
@@ -68,11 +71,29 @@
6871

6972
<div class="panel-terminal">
7073
<Box title="Preview" bind:contentEl={terminalContentEl}>
74+
<svelte:fragment slot="buttons">
75+
<ImportOptions />
76+
<ExportOptions />
77+
</svelte:fragment>
78+
7179
<TerminalWindow />
7280
</Box>
7381
</div>
7482
</main>
7583

84+
<SvelteToast
85+
options={{
86+
reversed: true,
87+
intro: { y: 192 },
88+
theme: {
89+
'--toastColor': 'mintcream',
90+
'--toastBackground': 'rgba(72,187,120,0.9)',
91+
'--toastBarBackground': '#2F855A',
92+
'--toastBarHeight': 0,
93+
},
94+
}}
95+
/>
96+
7697
<style lang="scss">
7798
.layout {
7899
display: flex;

src/components/ImportOptions.svelte

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<script lang="ts">
2+
import Modal from '~/components/common/Modal.svelte';
3+
import { toast } from '@zerodevx/svelte-toast';
4+
5+
import { ArrowForwardOutline, CodeDownloadOutline } from 'svelte-ionicons';
6+
import { importFromEnvArgs } from '~/data/import/importFromEnvArgs';
7+
8+
let textareaEl: HTMLTextAreaElement;
9+
let isModalOpen = false;
10+
11+
let errorMessage = '';
12+
13+
function validateInput(textareaValue: string) {
14+
if (textareaValue.startsWith('export ') || textareaValue.includes('FZF_DEFAULT_OPTS')) {
15+
errorMessage =
16+
'Invalid input. Text should not start with "export" and should not contain "FZF_DEFAULT_OPTS".';
17+
return false;
18+
}
19+
errorMessage = '';
20+
return true;
21+
}
22+
23+
function onClickImport() {
24+
if (!textareaEl) return;
25+
26+
const value = textareaEl.value;
27+
28+
if (validateInput(value)) {
29+
importFromEnvArgs(value);
30+
isModalOpen = false;
31+
32+
textareaEl.value = '';
33+
toast.push('Imported theme and colors!', {});
34+
}
35+
}
36+
</script>
37+
38+
<button
39+
class="export btn btn-primary"
40+
on:click={() => (isModalOpen = true)}
41+
on:change={() => (errorMessage = '')}
42+
>
43+
Import Options <CodeDownloadOutline size="16" />
44+
</button>
45+
46+
<!-- svelte-ignore a11y-no-static-element-interactions -->
47+
<div class="wrapper" on:mousemove|stopPropagation>
48+
<Modal bind:showModal={isModalOpen}>
49+
<h2 slot="header">Import Options</h2>
50+
51+
<div class="content">
52+
<p style="flex: 1;">
53+
Paste the <strong>contents</strong> of your <code>FZF_DEFAULT_OPTS</code> variable.
54+
</p>
55+
56+
<textarea
57+
bind:this={textareaEl}
58+
placeholder="Paste only the variable contents (inside the quotes)..."
59+
></textarea>
60+
61+
<div class="footer">
62+
<div class="error" style="word-wrap: break-word; overflow-wrap: break-word;">
63+
{errorMessage}
64+
</div>
65+
<button class="export btn btn-primary" on:click={onClickImport}>
66+
Import <ArrowForwardOutline size="16" />
67+
</button>
68+
</div>
69+
</div>
70+
</Modal>
71+
</div>
72+
73+
<style lang="scss">
74+
.content {
75+
display: flex;
76+
flex-direction: column;
77+
gap: 20px;
78+
height: 100%;
79+
}
80+
81+
textarea {
82+
display: block;
83+
width: 100%;
84+
height: 100%;
85+
}
86+
87+
.footer {
88+
display: flex;
89+
justify-content: space-between;
90+
gap: 20px;
91+
}
92+
</style>

src/components/TerminalWindow.svelte

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import { renderLines } from '~/utils/tui/renderLines';
77
import { addDelegateEventListener } from '~/utils/addDelegateEventListener';
88
import { toFzfColorName } from '~/utils/colors/toFzfColorName';
9-
import ExportOptions from '~/components/ExportOptions.svelte';
109
1110
// take all known color tokens and set them as css variables
1211
$: allTokenVariables = orderedColorTokens
@@ -114,8 +113,6 @@
114113
});
115114
</script>
116115

117-
<ExportOptions />
118-
119116
<div bind:this={wrapperEl} class="wrapper" style={allTokenVariables}>
120117
<div class="window-title" style:max-width={maxTerminalWidth}>
121118
<div class="dot red"></div>

src/components/common/Box.svelte

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,29 @@
55
export let contentStyle: string = '';
66
77
export let contentEl: HTMLDivElement | undefined = undefined;
8+
9+
const hasButtons = !!$$slots.buttons;
810
</script>
911

1012
<div class="box" style={style}>
11-
{#if title}
12-
<h2 class="title">{title}</h2>
13+
{#if hasButtons || title}
14+
<div class="header">
15+
{#if title}
16+
<h2 class="title">{title}</h2>
17+
{/if}
18+
19+
{#if hasButtons}
20+
<div class="buttons">
21+
<slot name="buttons" />
22+
</div>
23+
{/if}
24+
</div>
1325
{/if}
1426

1527
<div bind:this={contentEl} class="content" style={contentStyle}><slot /></div>
1628
</div>
1729

18-
<style>
30+
<style lang="scss">
1931
.box {
2032
background-color: var(--box-bg-color);
2133
padding: 15px;
@@ -24,12 +36,24 @@
2436
flex-direction: column;
2537
}
2638
39+
.header {
40+
display: flex;
41+
justify-content: space-between;
42+
align-items: center;
43+
margin-bottom: 15px;
44+
gap: 15px;
45+
46+
.buttons {
47+
display: flex;
48+
gap: 15px;
49+
}
50+
}
51+
2752
.title {
28-
margin-bottom: 1rem;
2953
font-size: 1.2rem;
3054
font-weight: bold;
31-
margin-bottom: 15px;
3255
margin-top: 0;
56+
margin-bottom: 0;
3357
}
3458
3559
.content {

src/components/common/Modal.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
let dialog: HTMLDialogElement;
66
77
$: if (dialog && showModal) dialog.showModal();
8+
9+
$: if (dialog && !showModal) dialog.close();
810
</script>
911

1012
<!-- svelte-ignore a11y-click-events-have-key-events a11y-no-noninteractive-element-interactions -->
@@ -50,7 +52,7 @@
5052
}
5153
5254
.wrapper {
53-
min-width: 700px;
55+
width: 700px;
5456
min-height: 500px;
5557
background-color: var(--bg-color);
5658
color: var(--text-color);

src/data/import/importFromEnvArgs.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1-
import parser from 'yargs-parser';
1+
import parser from 'yargs-parser/browser';
2+
import type { Options } from 'yargs-parser';
3+
import { colorsStore } from '~/data/colors.store';
24
import { fzfOptionsConfig } from '~/data/fzfOptions.config';
35
import { validateAndParseColors } from '~/data/import/validateAndParseColors';
46
import { validateAndParseThemeOptions } from '~/data/import/validateAndParseThemeOptions';
5-
import { isValidOption, type ThemeOption, type ThemeOptions } from '~/data/options.store';
7+
import {
8+
isValidOption,
9+
optionsStore,
10+
type ThemeOption,
11+
type ThemeOptions,
12+
} from '~/data/options.store';
613
import { toFzfColorName } from '~/utils/colors/toFzfColorName';
714

8-
export const importFromEnvArgs = (argsStr: string) => {
9-
const parsedObj = parser(argsStr.replace(/\n/g, ' '));
15+
const yargsParserOptions: Options = {
16+
configuration: {
17+
'parse-numbers': false,
18+
'camel-case-expansion': false,
19+
},
20+
};
21+
22+
export const parseEnvArgs = (argsStr: string) => {
23+
const parsedObj = parser(argsStr.replace(/\n/g, ' '), yargsParserOptions);
1024
const themeOptions: Partial<ThemeOptions> = {};
1125
const colors: Record<string, string> = {};
1226

@@ -40,3 +54,12 @@ export const importFromEnvArgs = (argsStr: string) => {
4054
colors: validateAndParseColors(colors),
4155
};
4256
};
57+
58+
export const importFromEnvArgs = (argsStr: string) => {
59+
const parsed = parseEnvArgs(argsStr);
60+
61+
optionsStore.updateAll(parsed.themeOptions);
62+
colorsStore.updateAllColors(parsed.colors);
63+
64+
return parsed;
65+
};

src/styles/main.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,10 @@ a:hover {
9191
pointer-events: none;
9292
}
9393
}
94+
95+
:root {
96+
--toastContainerTop: auto;
97+
--toastContainerRight: auto;
98+
--toastContainerBottom: 2rem;
99+
--toastContainerLeft: calc(50vw - 8rem);
100+
}

src/vendor.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ declare module '*.md' {
88
// Modify below per your usage
99
export { attributes, html };
1010
}
11+
12+
declare module 'yargs-parser/browser' {
13+
export * from 'yargs-parser';
14+
export { default } from 'yargs-parser';
15+
}

0 commit comments

Comments
 (0)