feat: tabs, state management

This commit is contained in:
Artemy Egorov 2024-07-29 22:14:05 +03:00
parent 9dfd66c14a
commit 107a8245e4
12 changed files with 414 additions and 51 deletions

View file

@ -43,24 +43,28 @@ body {
@apply ease-out duration-150;
@apply hover:bg-vigi-90;
@apply hover:px-2 hover:mx-1 hover:scale-125 hover:cursor-pointer;
@apply hover:px-2 hover:mx-1 hover:scale-125 cursor-pointer;
@apply active:bg-vigi-100;
}
.open-tabs {
@apply flex justify-between mt-2 mx-2;
}
.block {
@apply p-2 rounded-xl bg-vigi-60;
}
.sidebar {
@apply basis-1/5 shrink-0;
@apply shrink-0 grow-0 flex flex-col w-1/5;
@apply ease-out duration-100;
}
.sidebar.collapsed {
@apply basis-0;
@apply p-0 m-0;
@apply p-0 m-0 bg-transparent;
}
.top-bar {
@ -80,13 +84,54 @@ input::placeholder {
@apply text-vigi-40 focus:text-vigi-20;
}
.tabs {
@apply flex flex-col gap-1 mt-2 grow overflow-auto;
}
.tab {
@apply p-2 rounded-xl bg-vigi-50;
@apply cursor-pointer;
@apply ease-out duration-100;
@apply hover:bg-vigi-55;
@apply hover:px-4;
@apply flex items-center justify-between gap-2 w-full;
}
.close-button {
@apply p-1 rounded-lg;
@apply ease-out duration-100;
@apply hover:bg-vigi-90 active:bg-vigi-100;
}
/* .tab .close-button {
@apply text-transparent;
}
.tab:hover .close-button {
@apply text-vigi-0;
} */
.tab.active {
@apply bg-vigi-40 text-vigi-0 font-bold;
@apply hover:bg-vigi-45;
}
.tab-title {
@apply truncate;
}
::selection {
@apply bg-vigi-60;
}
/* width */
::-webkit-scrollbar {
width: 20px;
width: 15px;
}
/* Track */
@ -96,12 +141,12 @@ input::placeholder {
/* Handle */
::-webkit-scrollbar-thumb {
@apply rounded-xl bg-vigi-90 bg-clip-content;
@apply rounded-xl bg-vigi-70 bg-clip-content;
border: 6px solid transparent;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
@apply bg-vigi-100;
@apply bg-vigi-75;
border: 5px solid transparent;
}

View file

@ -1,16 +1,45 @@
<script>
<script lang="ts">
import { slide } from "svelte/transition";
import Block from "./Block.svelte";
import WindowControls from "./WindowControls.svelte";
import type { StateTab } from "$lib/types";
import { state } from "$lib/stores";
import Tab from "./Tab.svelte";
import { addTab } from "$lib/utils";
import Button from "./Button.svelte";
import Add from "$lib/icons/Add.svelte";
export let sidebarOpen = true;
export let collapsed = true;
let tabs: StateTab[] = [];
let currentTabIndex = 0;
state.subscribe(async (state) => {
tabs = state.tabs;
currentTabIndex = state.current_tab_index;
if (tabs.length === 0) {
await addTab();
}
});
</script>
<Block className={`sidebar${sidebarOpen ? "" : " collapsed"}`} draggable>
{#if sidebarOpen}
<div transition:slide={{ axis: "x", duration: 100 }}>
<WindowControls />
<Block className={`sidebar${collapsed ? "" : " collapsed"}`} draggable>
{#if collapsed}
<WindowControls />
<div class="open-tabs">
Open tabs
<Button onClick={addTab}>
<Add />
</Button>
</div>
<div class="tabs">
{#each tabs as tab, i (tab.id)}
<Tab {tab} active={currentTabIndex === i} id={i} />
{/each}
</div>
{/if}
</Block>

View file

@ -0,0 +1,46 @@
<script lang="ts">
import type { StateTab } from "$lib/types";
import { removeTab, selectTab } from "$lib/utils";
import { slide } from "svelte/transition";
import Close from "$lib/icons/Close.svelte";
import Button from "./Button.svelte";
export let active = false;
export let tab: StateTab;
export let id: number;
let tabElement: HTMLButtonElement;
let hovered = false;
</script>
<div
class="flex gap-1 items-center"
on:mouseenter={() => (hovered = true)}
on:mouseleave={() => (hovered = false)}
role="tab"
tabindex={id}
>
<button
class="tab"
class:active
transition:slide={{ duration: 100 }}
bind:this={tabElement}
on:click={() => {
selectTab(id);
}}
>
<div class="tab-title">
{tab.title}
</div>
</button>
{#if hovered}
<button
class="close-button"
transition:slide={{ duration: 100, axis: "x" }}
on:click={() => removeTab(id)}><Close /></button
>
{/if}
</div>

17
src/lib/icons/Add.svelte Normal file
View file

@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
{...$$props}
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M12 4v16m-8-8h16"
color="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 300 B

View file

@ -1,3 +1,6 @@
import { writable } from "svelte/store";
import { writable, type Writable } from "svelte/store";
import type { VigiState } from "./types";
export const topBarInput = writable("");
export const topBarInput: Writable<string> = writable("");
export const state: Writable<VigiState> = writable();

14
src/lib/types.ts Normal file
View file

@ -0,0 +1,14 @@
export interface VigiState {
current_tab_index: number;
tabs: StateTab[];
favorites_tabs: StateTab[];
}
type TabType = "HomePage" | "Text";
export interface StateTab {
ty: TabType;
title: string;
url: string;
id: number;
}

32
src/lib/utils.ts Normal file
View file

@ -0,0 +1,32 @@
import { invoke } from "@tauri-apps/api";
import { state, topBarInput } from "./stores";
import type { StateTab, VigiState } from "./types";
export function updateVigiState() {
invoke("get_state")
.then((r) => {
let st = r as VigiState;
state.set(st);
topBarInput.set(st.tabs[st.current_tab_index].url);
})
.catch((err) => console.log(err));
}
export async function addTab() {
await invoke("add_tab");
updateVigiState();
}
export async function selectTab(index: number) {
await invoke("select_tab", { index });
updateVigiState();
}
export async function removeTab(index: number) {
await invoke("remove_tab", { index });
updateVigiState();
}

View file

@ -8,14 +8,16 @@
import { invoke } from "@tauri-apps/api/tauri";
import { topBarInput } from "$lib/stores";
import { updateVigiState } from "$lib/utils";
let sidebarOpen = true;
let inputValue = "";
let isLoading = false;
let data: Root = [];
updateVigiState();
document.addEventListener("keypress", (e: KeyboardEvent) => {
const formElements = ["INPUT", "TEXTAREA", "SELECT", "OPTION"];
if (formElements.includes((e.target as Element).tagName)) {
@ -34,6 +36,9 @@
.catch((err) => {
data = [{ id: 0, body: "Error: " + err, argument: null }];
isLoading = false;
})
.finally(() => {
updateVigiState();
});
});
</script>
@ -42,7 +47,7 @@
class={`common-window${sidebarOpen ? "" : " collapsed"}`}
data-tauri-drag-region
>
<Sidebar bind:sidebarOpen />
<Sidebar bind:collapsed={sidebarOpen} />
<div class="main-window">
<TopBar bind:sidebarOpen />