Main view restructure
mellobacon committed
Nov 25, 2022 at 14:05 UTC
82f50dfdfe52002eada81d37682491af926eb01c
11 files changed
+814
-6
src/App.svelte
+2
-3
@@ -1,7 +1,7 @@
1
<script lang="ts">
2
import Header from "./components/Header/Header.svelte";
3
import Sidebar from "./components/Sidebar/Sidebar.svelte";
4
- import MainContainer from "./components/Content/MainContainer.svelte";
4
+ import MainContainer from "./components/View/MainView.svelte";
5
import "carbon-components-svelte/css/g100.css";
6
import { Pane, Splitpanes } from 'svelte-splitpanes';
7
import SidebarView from "./components/Sidebar/SidebarView.svelte";
@@ -13,7 +13,7 @@
13
<Sidebar />
14
<Splitpanes theme="editor-pane">
15
{#if $showsidebarview}
16
- <Pane size={25} snapSize={5}>
16
+ <Pane size={25} minSize={10}>
17
<SidebarView title={$tool.tabname} content={$tool.content}></SidebarView>
18
</Pane>
19
{/if}
@@ -25,6 +25,5 @@
25
<style>
26
#main {
27
display: flex;
28
- height: calc(100% - 2rem);
28
}
29
</style>
\ No newline at end of file
src/components/Editor/CodeMirrorEditor.svelte
new
+106
@@ -0,0 +1,106 @@
1
+<script lang="ts">
2
+ import { createEventDispatcher, onMount, tick } from "svelte";
3
+ import { basicSetup } from "codemirror";
4
+ import { EditorView, keymap } from "@codemirror/view";
5
+ import { indentWithTab } from "@codemirror/commands";
6
+ import { EditorState, Compartment } from "@codemirror/state";
7
+ import { default_theme } from "./scripts/DefaultTheme";
8
+ import { line_info } from "./scripts/Editor";
9
+
10
+ export let hidden = false;
11
+ let editorElement;
12
+ let editorView: EditorView;
13
+ export let content = "";
14
+ export let lang = new Compartment();
15
+
16
+ export function setLanguageMode(mode) {
17
+ editorView.dispatch({
18
+ effects: lang.reconfigure(mode)
19
+ })
20
+ }
21
+ export async function focus() {
22
+ await tick();
23
+ await tick();
24
+ editorView.focus();
25
+ getLineInfo();
26
+ }
27
+ function getLineInfo() {
28
+ let linenumber = editorView.state.doc.lineAt(editorView.state.selection.main.head).number;
29
+ let colnumber = editorView.state.selection.ranges[0].head - editorView.state.doc.lineAt(editorView.state.selection.main.head).from
30
+ line_info.set({line: linenumber.toString(), col: (colnumber + 1).toString()})
31
+ }
32
+ async function updateDom() {
33
+ await tick();
34
+ let filecontent = "";
35
+ for (let text of editorView.state.doc) {
36
+ filecontent += `${text} `;
37
+ }
38
+ dispatch("input", filecontent);
39
+ }
40
+ let dispatch = createEventDispatcher();
41
+
42
+ onMount(() => {
43
+ editorView = new EditorView({
44
+ state: EditorState.create({
45
+ extensions: [basicSetup, default_theme, keymap.of([indentWithTab]), lang.of([])],
46
+ doc: content
47
+ }),
48
+ parent: editorElement,
49
+ });
50
+ });
51
+</script>
52
+<div class="editor" class:hidden bind:this={editorElement}
53
+on:input={async (e) => {
54
+ await updateDom();
55
+ getLineInfo();
56
+}}
57
+on:keydown={async (e) => {
58
+ let key = e.code;
59
+ switch(key) {
60
+ case "Backspace": case "Enter":
61
+ await updateDom();
62
+ getLineInfo();
63
+ break;
64
+ case "ArrowRight": case "ArrowLeft": case "ArrowDown": case "ArrowUp":
65
+ getLineInfo();
66
+ break;
67
+ }
68
+}}
69
+on:mousedown = {(e) => {
70
+ getLineInfo();
71
+}}
72
+ />
73
+
74
+<style>
75
+ .editor {
76
+ height: 100%;
77
+ width: 100%;
78
+ }
79
+ .hidden {
80
+ display: none;
81
+ }
82
+ :global(.cm-editor:focus),
83
+ :global(.cm-focused) {
84
+ outline: none !important;
85
+ }
86
+ :global(.cm-editor),
87
+ :global(.cm-wrap) {
88
+ height: 100%;
89
+ }
90
+ :global(.cm-scroller) {
91
+ overflow-y: overlay;
92
+ overflow-x: overlay !important;
93
+ }
94
+ :global(.cm-scroller)::-webkit-scrollbar {
95
+ width: 20px;
96
+ }
97
+ :global(.cm-scroller)::-webkit-scrollbar-thumb {
98
+ background-color: #4c4c4c38;;
99
+ }
100
+ :global(.cm-scroller)::-webkit-scrollbar-corner {
101
+ background-color: transparent;
102
+ }
103
+ :global(.cm-content) {
104
+ padding: 0 !important;
105
+ }
106
+</style>
src/components/Editor/Editor.svelte
new
+17
@@ -0,0 +1,17 @@
1
+<script lang="ts">
2
+ import { hidden } from "../Tabs/scripts/Tab";
3
+</script>
4
+
5
+<div id="tabview" class:hidden={$hidden}></div>
6
+
7
+<style>
8
+ #tabview {
9
+ width: 100%;
10
+ height: 100%;
11
+ background-color: #1C1C1C;
12
+ z-index: 1;
13
+ }
14
+ .hidden {
15
+ visibility: hidden;
16
+ }
17
+</style>
\ No newline at end of file
src/components/Editor/scripts/DefaultTheme.ts
new
+209
@@ -0,0 +1,209 @@
1
+import { EditorView } from "@codemirror/view";
2
+import type { Extension } from "@codemirror/state";
3
+import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
4
+import { tags as t } from "@lezer/highlight";
5
+
6
+const bg = "#1c1c1c",
7
+ cl = "#282a2e",
8
+ sel = "#373b41",
9
+ fg = "#c5c8c6",
10
+ com = "#969896",
11
+ red = "#cc6666",
12
+ orange = "#fff9f5",
13
+ green = "#b5bd68",
14
+ aqua = "#8abeb7",
15
+ blue = "#81a2be",
16
+ purple = "#b294bb";
17
+
18
+const defaultTheme = EditorView.theme(
19
+ {
20
+ "*": {
21
+ fontFamily: '"Ubuntu Mono", monospace'
22
+ },
23
+
24
+ "&": {
25
+ color: fg,
26
+ backgroundColor: bg
27
+ },
28
+
29
+ ".cm-content": {
30
+ caretColor: orange
31
+ },
32
+
33
+ "&.cm-focused .cm-cursor": {
34
+ borderLeftColor: orange
35
+ },
36
+
37
+ "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, ::selection": {
38
+ backgroundColor: sel
39
+ },
40
+
41
+ ".cm-panels": {
42
+ backgroundColor: bg,
43
+ color: fg
44
+ },
45
+
46
+ ".cm-panels.cm-panels-top": {
47
+ borderBottom: "2px solid black"
48
+ },
49
+
50
+ ".cm-panels.cm-panels-bottom": {
51
+ borderTop: "2px solid black"
52
+ },
53
+
54
+ ".cm-searchMatch": {
55
+ backgroundColor: "#72a1ff59",
56
+ outline: "1px solid #457dff"
57
+ },
58
+
59
+ ".cm-searchMatch.cm-searchMatch-selected": {
60
+ backgroundColor: "#6199ff2f"
61
+ },
62
+
63
+ ".cm-activeLine": {
64
+ backgroundColor: "transparent",
65
+ boxShadow: "inset 0px 0px 0 0.5px #3f3f3f"
66
+ },
67
+
68
+ ".cm-selectionMatch": {
69
+ backgroundColor: "#aafe661a"
70
+ },
71
+
72
+ ".cm-matchingBracket, .cm-nonmatchingBracket": {
73
+ backgroundColor: "#bad0f847",
74
+ outline: "1px solid #515a6b"
75
+ },
76
+
77
+ ".cm-gutters": {
78
+ backgroundColor: bg,
79
+ color: com,
80
+ border: "none"
81
+ },
82
+
83
+ ".cm-activeLineGutter": {
84
+ backgroundColor: bg,
85
+ color: "white"
86
+ },
87
+
88
+ ".cm-foldPlaceholder": {
89
+ backgroundColor: "transparent",
90
+ border: "none",
91
+ color: "#ddd"
92
+ },
93
+
94
+ ".cm-tooltip": {
95
+ border: "1px solid #181a1f",
96
+ backgroundColor: bg
97
+ },
98
+ ".cm-tooltip-autocomplete": {
99
+ "& > ul > li[aria-selected]": {
100
+ backgroundColor: bg,
101
+ color: fg
102
+ }
103
+ }
104
+ },
105
+ { dark: true }
106
+);
107
+
108
+const defaultHighlightStyle = HighlightStyle.define([
109
+ {
110
+ tag: t.keyword,
111
+ color: purple
112
+ },
113
+
114
+ {
115
+ tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
116
+ color: red
117
+ },
118
+
119
+ {
120
+ tag: [t.function(t.variableName), t.labelName],
121
+ color: blue
122
+ },
123
+
124
+ {
125
+ tag: [t.color, t.constant(t.name), t.standard(t.name)],
126
+ color: orange
127
+ },
128
+
129
+ {
130
+ tag: [t.definition(t.name), t.separator],
131
+ color: fg
132
+ },
133
+
134
+ {
135
+ tag: [
136
+ t.typeName,
137
+ t.className,
138
+ t.number,
139
+ t.changed,
140
+ t.annotation,
141
+ t.modifier,
142
+ t.self,
143
+ t.namespace
144
+ ],
145
+ color: orange
146
+ },
147
+
148
+ {
149
+ tag: [
150
+ t.operator,
151
+ t.operatorKeyword,
152
+ t.url,
153
+ t.escape,
154
+ t.regexp,
155
+ t.link,
156
+ t.special(t.string)
157
+ ],
158
+ color: aqua
159
+ },
160
+
161
+ {
162
+ tag: [t.meta, t.comment],
163
+ color: com
164
+ },
165
+
166
+ {
167
+ tag: t.strong,
168
+ fontWeight: "bold"
169
+ },
170
+
171
+ {
172
+ tag: t.emphasis,
173
+ fontStyle: "italic"
174
+ },
175
+
176
+ {
177
+ tag: t.strikethrough,
178
+ textDecoration: "line-through"
179
+ },
180
+
181
+ {
182
+ tag: t.link,
183
+ color: com,
184
+ textDecoration: "underline"
185
+ },
186
+
187
+ {
188
+ tag: t.heading,
189
+ fontWeight: "bold",
190
+ color: red
191
+ },
192
+
193
+ {
194
+ tag: [t.atom, t.bool, t.special(t.variableName)],
195
+ color: orange
196
+ },
197
+
198
+ {
199
+ tag: [t.processingInstruction, t.string, t.inserted],
200
+ color: green
201
+ },
202
+
203
+ {
204
+ tag: t.invalid,
205
+ color: "#ffffff"
206
+ }
207
+]);
208
+
209
+export const default_theme: Extension = [defaultTheme, syntaxHighlighting(defaultHighlightStyle)];
\ No newline at end of file
src/components/Editor/scripts/Editor.ts
new
+26
@@ -0,0 +1,26 @@
1
+import langlist from "../../../scripts/languages/languages.json";
2
+import { languages } from "@codemirror/language-data";
3
+import { writable } from 'svelte/store';
4
+
5
+export let line_info = writable({line: "-", col: "-"});
6
+
7
+let keys = Object.keys(langlist);
8
+export function getLang(ext: string) {
9
+ for (let key of keys) {
10
+ let extensions = langlist[key].extensions;
11
+ if (extensions && extensions.includes(`.${ext}`)) {
12
+ return `${key}`;
13
+ }
14
+ }
15
+}
16
+
17
+export async function getLangMode(language: string) {
18
+ // TODO: So apparently not every language is supported in CodeMirror. I need to find a way to support that
19
+ let mode = languages.find(l => l.name === language);
20
+ if (mode) {
21
+ return await mode.load();
22
+ }
23
+ else {
24
+ return [];
25
+ }
26
+}
\ No newline at end of file
src/components/Tabs/EditorTabs.svelte
new
+49
@@ -0,0 +1,49 @@
1
+<script lang="ts">
2
+ import { Sortable } from "sortablejs";
3
+ import { onMount } from "svelte";
4
+ import Tab from "./Tab.svelte";
5
+ import { hidden, tabs } from "./scripts/Tab";
6
+ let tabcontainer;
7
+ onMount(() => {
8
+ Sortable.create(tabcontainer, {
9
+ draggable: ".tab",
10
+ animation: 150,
11
+ forceFallback: true,
12
+ easing: "cubic-bezier(1, 0, 0, 1)",
13
+ sort: true
14
+ })
15
+ })
16
+</script>
17
+
18
+<div id="editor-tabs" class:hidden={$hidden}>
19
+ <div id="tablist" bind:this={tabcontainer}>
20
+ {#each $tabs as tab}
21
+ <Tab label={tab.label} path={tab.path} active={tab.active} id={tab.id} unsaved={tab.saved} />
22
+ {/each}
23
+ </div>
24
+</div>
25
+
26
+<style lang="scss">
27
+ .hidden {
28
+ visibility: hidden;
29
+ }
30
+ #editor-tabs {
31
+ width: -webkit-fill-available;
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: space-between;
35
+ position: absolute;
36
+ box-shadow: inset 0px -1px 0 0 #333;
37
+ #tablist {
38
+ position: absolute;
39
+ height: 100%;
40
+ display: flex;
41
+ &::-webkit-scrollbar {
42
+ height: 4px;
43
+ }
44
+ &::-webkit-scrollbar-thumb {
45
+ background-color: #ffffff12;
46
+ }
47
+ }
48
+ }
49
+</style>
src/components/Tabs/Tab.svelte
new
+109
@@ -0,0 +1,109 @@
1
+<script lang="ts">
2
+ import { closeTab, setActive } from "./scripts/Tab";
3
+ import TabMenu from "./TabMenu.svelte";
4
+ export let id = 0;
5
+ export let label = "Untitled-1";
6
+ export let path = "";
7
+ export let active = false;
8
+ export let unsaved = false;
9
+ let tab;
10
+</script>
11
+<div bind:this={tab} title={path} id={`tab-${id}`} class="tab" class:tab-active={active} class:unsaved={unsaved}>
12
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
13
+ <div class="tab-content" on:click = {
14
+ () => {
15
+ setActive(id);
16
+ }
17
+ }>
18
+ <span class="tab-label">{label}</span>
19
+ {#if unsaved}
20
+ <span></span>
21
+ {/if}
22
+ </div>
23
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
24
+ <div class="close-tab" on:click={() => {
25
+ closeTab(id);
26
+ }}>
27
+ <span></span>
28
+ </div>
29
+</div>
30
+
31
+<TabMenu target={tab} id={id} filename={label} filepath={path} />
32
+
33
+<style lang="scss">
34
+ .tab {
35
+ background-color: #1c1c1c;
36
+ height: 100%;
37
+ min-width: min-content;
38
+ flex-grow: 0.05;
39
+ display: flex;
40
+ overflow: hidden;
41
+ color: white;
42
+ justify-content: space-between;
43
+ align-items: center;
44
+ cursor: pointer;
45
+ padding: 0 10px;
46
+ box-shadow: inset 0px -0.5px 0 0 #bdd4ff;
47
+ &:not(.active):hover {
48
+ background-color: #2b2b2b;
49
+ }
50
+ }
51
+ .tab:not(.tab-active):hover {
52
+ background-color: #2b2b2b;
53
+ }
54
+ .tab-content::-webkit-scrollbar {
55
+ height: 4px;
56
+ }
57
+ .tab-content::-webkit-scrollbar {
58
+ background-color: #1b5fdd;
59
+ }
60
+ .tab-content {
61
+ display: flex;
62
+ justify-content: center;
63
+ align-items: center;
64
+ overflow-x: overlay;
65
+ overflow-y: hidden;
66
+ height: 100%;
67
+ padding-left: 2px;
68
+ :nth-child(2) {
69
+ display: block;
70
+ width: 6px;
71
+ height: 6px;
72
+ background-color: white;
73
+ border-radius: 50%;
74
+ left: -11px;
75
+ top: 0.5px;
76
+ position: relative;
77
+ }
78
+ }
79
+ .tab-active {
80
+ background-color: rgb(28, 28, 28);
81
+ box-shadow: inset 0px -2px 0 0 #1b5fdd !important;
82
+ }
83
+ .tab-active.unsaved {
84
+ box-shadow: inset 0px -2px 0 0 #dd6f1b !important;
85
+ }
86
+ .unsaved {
87
+ box-shadow: inset 0px -0.5px 0 0 #dd6f1b;
88
+ }
89
+ .tab-label {
90
+ text-overflow: ellipsis;
91
+ white-space: nowrap;
92
+ padding-right: 20px;
93
+ }
94
+ .close-tab span::before {
95
+ content: "\2715";
96
+ font-size: 13px;
97
+ }
98
+ .close-tab span:hover {
99
+ color: gray;
100
+ }
101
+ .close-tab {
102
+ width: 2rem;
103
+ margin-left: -1rem;
104
+ display: flex;
105
+ justify-content: center;
106
+ position: relative;
107
+ left: 10px;
108
+ }
109
+</style>
\ No newline at end of file
src/components/Tabs/TabMenu.svelte
new
+57
@@ -0,0 +1,57 @@
1
+<script lang="ts">
2
+ import { ContextMenuOption } from "carbon-components-svelte";
3
+ import ContextMenu from "../ContextMenu/ContextMenu.svelte";
4
+ import CopyFile from "carbon-icons-svelte/lib/CopyFile.svelte";
5
+ import Cut from "carbon-icons-svelte/lib/Cut.svelte";
6
+ import { clipboard, path, invoke } from "@tauri-apps/api";
7
+ import { closeTab, setActive } from "./scripts/Tab";
8
+ export let id: number;
9
+ export let target;
10
+ export let filename: string;
11
+ export let filepath: string;
12
+
13
+ async function copyToClipboard(input) {
14
+ await clipboard.writeText(input);
15
+ }
16
+</script>
17
+
18
+<ContextMenu {target}>
19
+ <ContextMenuOption indented icon={CopyFile} labelText="Close Tab" on:click={() => {
20
+ closeTab(id);
21
+ }}>
22
+ <span class="contextshortcut" slot="shortcutText">Ctrl + F4</span>
23
+ </ContextMenuOption>
24
+ <ContextMenuOption indented icon={Cut} labelText="Close Others" on:click={() => {
25
+ let tabs = document.getElementsByClassName("tab");
26
+ for (const tab of tabs) {
27
+ let t = tab.id;
28
+ let tabid = parseInt(t.split("-").pop());
29
+ if (tabid !== id) {
30
+ closeTab(tabid);
31
+ }
32
+ }
33
+ setActive(id);
34
+ }} ></ContextMenuOption>
35
+ <ContextMenuOption indented labelText="Close Saved Tabs" on:click={() => {}}>
36
+ <span class="contextshortcut" slot="shortcutText">Ctrl + X S</span>
37
+ </ContextMenuOption>
38
+ <ContextMenuOption indented labelText="Close All Tabs" on:click={() => {}}>
39
+ <span class="contextshortcut" slot="shortcutText">Ctrl + X A</span>
40
+ </ContextMenuOption>
41
+ <!--TODO: Make this relative instead of file name. Am lazy-->
42
+ <ContextMenuOption on:click={() => copyToClipboard(filename)}>
43
+ <span slot="labelText" title={filename}>Copy File Name</span>
44
+ </ContextMenuOption>
45
+ <ContextMenuOption on:click={() => copyToClipboard(filepath)}>
46
+ <span slot="labelText" title={filepath}>Copy Absolute Path</span>
47
+ </ContextMenuOption>
48
+ <ContextMenuOption labelText="Show in Explorer" on:click={() => {
49
+ invoke("open_in_explorer",{ path:filepath})
50
+ }}></ContextMenuOption>
51
+</ContextMenu>
52
+
53
+<style>
54
+ .contextshortcut {
55
+ color: #8c8c8c;
56
+ }
57
+</style>
\ No newline at end of file
src/components/Tabs/scripts/Tab.ts
new
+196
@@ -0,0 +1,196 @@
1
+import { writable } from 'svelte/store';
2
+import { EditorFile, getFileData } from '../../../scripts/EditorFile'
3
+import CodeMirrorEditor from '../../Editor/CodeMirrorEditor.svelte';
4
+import { writeFile } from '@tauri-apps/api/fs';
5
+import { getLang, getLangMode } from '../../Editor/scripts/Editor';
6
+
7
+let id = 0;
8
+let activeid;
9
+
10
+export let file_language = writable("");
11
+export let linefeed = writable("");
12
+export let tablist: Tab[] = [];
13
+export let tabs = writable([]);
14
+export let hidden = writable(true);
15
+export let isfile = writable(false);
16
+
17
+class Tab {
18
+ id: number;
19
+ label: string;
20
+ active: boolean;
21
+ constructor(id: number, label: string = "") {
22
+ this.id = id;
23
+ this.label = label === "" ? `Untitled-${id}` : label;
24
+ }
25
+}
26
+
27
+export class FileTab extends Tab {
28
+ path: string;
29
+ language: string = "Plain Text";
30
+ linefeed: string;
31
+ saved: boolean = true;
32
+ editor: CodeMirrorEditor | null;
33
+ editorcontent: string;
34
+ constructor(id: number, file: EditorFile, editor, saved: boolean = true) {
35
+ super(id, file.filename);
36
+ this.path = file.path;
37
+ this.saved = saved;
38
+ this.editor = editor;
39
+ this.editorcontent = file.content;
40
+
41
+ let filepath = file.path.split(".");
42
+ let extension = "txt";
43
+ if (filepath.length !== 1) {
44
+ extension = filepath.at(-1);
45
+ }
46
+
47
+ this.language = getLang(extension)
48
+ this.linefeed = file.linefeed;
49
+
50
+ let _ = undefined;
51
+ this.editor.$on("input", (e) => {
52
+ clearTimeout(_);
53
+ _ = setTimeout(() => {
54
+ this.editorcontent = e.detail;
55
+ if (this.path !== "") {
56
+ writeFile(this.path, e.detail);
57
+ console.log(`${this.label} saved`);
58
+ if (!this.saved) {
59
+ this.saved = true;
60
+ setActive(this.id);
61
+ }
62
+ }
63
+ else {
64
+ this.saved = false;
65
+ }
66
+ }, 1000)
67
+ })
68
+ }
69
+
70
+ async setLanguage(lang: string) {
71
+ let mode = await getLangMode(lang);
72
+ this.editor.setLanguageMode(mode);
73
+
74
+ file_language.set(lang);
75
+ this.language = lang;
76
+ }
77
+ setFile(file: EditorFile) {
78
+ this.label = file.filename === "" ? `Untitled-${this.id}` : file.filename;
79
+ this.path = file.path;
80
+ let filepath = file.path.split(".");
81
+ let extension = "txt";
82
+ if (filepath.length !== 1) {
83
+ extension = filepath.at(-1);
84
+ }
85
+ this.language = getLang(extension);
86
+
87
+ this.linefeed = file.linefeed;
88
+ }
89
+ focusTab() {
90
+ file_language.set(this.language);
91
+ linefeed.set(this.linefeed);
92
+ this.editor.focus();
93
+ }
94
+ updateEditorVisibility(id: number) {
95
+ this.editor.$set({ hidden: !(this.id === id) })
96
+ }
97
+}
98
+export class SettingsTab extends Tab {
99
+ content: string;
100
+ constructor(id: number, label: string, content: string) {
101
+ super(id, label);
102
+ this.content = content;
103
+ }
104
+}
105
+
106
+export async function addFileTab(path = "") {
107
+ for (let t of tablist) {
108
+ if ((t as FileTab).path === path) {
109
+ setActive(t.id);
110
+ }
111
+ }
112
+ let file = await getFileData(path);
113
+ let editor = new CodeMirrorEditor({ target: document.getElementById("tabview"), props: { content: file.content } });
114
+ let tab = new FileTab(id, file, editor, path !== "");
115
+ await tab.setLanguage(tab.language);
116
+ tablist = [...tablist, tab];
117
+
118
+ refreshTabs();
119
+}
120
+
121
+export function addSettingsTab() {
122
+ let content = "";
123
+ let tab = new SettingsTab(id, "Settings", content);
124
+ tablist = [...tablist, tab];
125
+
126
+ refreshTabs();
127
+}
128
+
129
+export function setActive(id: number) {
130
+ for (let tab of tablist) {
131
+ if (tab.id === id) {
132
+ activeid = id;
133
+ tab.active = true;
134
+ if (tab instanceof FileTab) {
135
+ let t = tab as FileTab;
136
+ isfile.set(true);
137
+ t.focusTab();
138
+ }
139
+ else {
140
+ isfile.set(false);
141
+ }
142
+ }
143
+ else {
144
+ tab.active = false;
145
+ }
146
+ }
147
+ tabs.set(tablist);
148
+ updateEditorVisibility();
149
+}
150
+
151
+export function closeTab(tabid: number) {
152
+ if (activeid === tabid) {
153
+ for (let i = 0; i <= tablist.length - 1; i++) {
154
+ if (tablist[i].id === tabid && tablist[i + 1]) {
155
+ setActive(tablist[i + 1].id);
156
+ break;
157
+ }
158
+ else if (tablist[i].id === tabid && tablist[i - 1]) {
159
+ setActive(tablist[i - 1].id);
160
+ break;
161
+ }
162
+ }
163
+ }
164
+
165
+ for (let tab of tablist) {
166
+ if (tab.id === tabid) {
167
+ (tab as FileTab).editor.$destroy();
168
+ break;
169
+ }
170
+ }
171
+ tablist = tablist.filter(t => t.id !== tabid);
172
+ tabs.set(tablist);
173
+
174
+ updateEditorVisibility();
175
+ if (tablist.length === 0) {
176
+ hidden.set(true);
177
+ isfile.set(false);
178
+ id = 0;
179
+ }
180
+}
181
+
182
+function refreshTabs() {
183
+ if (tablist.length > 0) {
184
+ hidden.set(false);
185
+ isfile.set(true);
186
+ }
187
+ tabs.set(tablist);
188
+ setActive(id);
189
+ id++;
190
+}
191
+
192
+function updateEditorVisibility() {
193
+ for (let tab of tablist) {
194
+ (tab as FileTab).updateEditorVisibility(activeid);
195
+ }
196
+}
src/components/View/MainView.svelte
new
+40
@@ -0,0 +1,40 @@
1
+<script lang="ts">
2
+ import { Splitpanes, Pane } from "svelte-splitpanes";
3
+ import Editor from "../Editor/Editor.svelte";
4
+ import Footer, { showpanel, tool } from "../Footer/Footer.svelte";
5
+ import EditorTabs from "../Tabs/EditorTabs.svelte";
6
+
7
+ let panelsize = 20;
8
+ function updatePanelSize(event) {
9
+ if ($showpanel) {
10
+ panelsize = event.detail[1].size;
11
+ }
12
+ }
13
+</script>
14
+
15
+<div id="container">
16
+ <Splitpanes theme="editor-pane" horizontal on:resized={updatePanelSize}>
17
+ <Pane>
18
+ <div class="main">
19
+ <EditorTabs />
20
+ <Editor />
21
+ </div>
22
+ </Pane>
23
+ {#if $showpanel}
24
+ <Pane bind:size={panelsize} minSize={4}><div class="panel">{$tool.content}</Pane>
25
+ {/if}
26
+ </Splitpanes>
27
+ <Footer></Footer>
28
+</div>
29
+
30
+<style>
31
+ #container {
32
+ height: 100%;
33
+ overflow: hidden;
34
+ }
35
+ .main {
36
+ background-image: url("/assets/images/Watermark(3).png");
37
+ background-repeat: no-repeat;
38
+ background-position: center;
39
+ }
40
+</style>
\ No newline at end of file
src/scripts/EditorFile.ts
+3
-3
@@ -1,8 +1,8 @@
1
import { readTextFile, writeFile } from "@tauri-apps/api/fs";
2
import { sep } from "@tauri-apps/api/path";
3
import { dialog } from "@tauri-apps/api";
4
-import { setActive, tablist } from "../components/Content/Editor/scripts/Tab";
5
-import type { FileTab } from "../components/Content/Editor/scripts/Tab";
4
+import { setActive, tablist } from "../components/Tabs/scripts/Tab";
5
+import type { FileTab } from "../components/Tabs/scripts/Tab";
6
7
export class EditorFile {
8
filename: string;
@@ -17,7 +17,7 @@ export class EditorFile {
17
}
18
}
19
20
-export async function openFile() {
20
+export async function getFile() {
21
let path = await dialog.open() as string;
22
if (path === undefined) return;
23
return path;