feat: text-color

This commit is contained in:
Artemy Egorov 2024-07-31 14:03:32 +03:00
parent 9c8437851d
commit a23bead7d8
13 changed files with 373 additions and 220 deletions

View file

@ -58,7 +58,7 @@ jobs:
TAURI_KEY_PASSWORD: "" TAURI_KEY_PASSWORD: ""
with: with:
tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version. tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version.
releaseName: "Vigi v__VERSION__" releaseName: "vigi v__VERSION__"
releaseBody: "See the assets to download this version and install." releaseBody: "See the assets to download this version and install."
releaseDraft: true releaseDraft: true
prerelease: false prerelease: false

View file

@ -1,7 +0,0 @@
{
"recommendations": [
"svelte.svelte-vscode",
"tauri-apps.tauri-vscode",
"rust-lang.rust-analyzer"
]
}

View file

@ -1,3 +0,0 @@
{
"svelte.enable-ts-plugin": true
}

View file

@ -140,7 +140,7 @@ impl VigiState {
)], )],
) )
} else { } else {
todo!(); Err(VigiError::Parse)?
} }
}; };

View file

@ -2,109 +2,195 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
:root { /* Theme */
--min: #96e28a;
--max: #193815;
/* --min: #8a9fe2; :root {
--max: #151a38; */ /* Theme Colors */
/* Green */
--min-bg: #96e28a;
--max-bg: #193815;
--max-text: #bef5b5;
--min-text: #fff;
/* Dark */
/* --min: #818181;
--max: #000; */
/* Blue */
/* --min: #8a9fe2;
--max: #151a38; */
/* Red */
/* --min: #e28a8a;
--max: #641515; */
/* End Theme Colors */
} }
/* Theme Classes */
.color-vigi-0 {
@apply text-vigi-0 bg-vigi-0;
}
.color-vigi-5 {
@apply text-vigi-5 bg-vigi-5;
}
.color-vigi-10 {
@apply text-vigi-10 bg-vigi-10;
}
.color-vigi-15 {
@apply text-vigi-15 bg-vigi-15;
}
.color-vigi-20 {
@apply text-vigi-20 bg-vigi-20;
}
.color-vigi-25 {
@apply text-vigi-25 bg-vigi-25;
}
.color-vigi-30 {
@apply text-vigi-30 bg-vigi-30;
}
.color-vigi-35 {
@apply text-vigi-35 bg-vigi-35;
}
.color-vigi-40 {
@apply text-vigi-40 bg-vigi-40;
}
.color-vigi-45 {
@apply text-vigi-45 bg-vigi-45;
}
.color-vigi-50 {
@apply text-vigi-50 bg-vigi-50;
}
.color-vigi-55 {
@apply text-vigi-55 bg-vigi-55;
}
.color-vigi-60 {
@apply text-vigi-60 bg-vigi-60;
}
.color-vigi-65 {
@apply text-vigi-65 bg-vigi-65;
}
.color-vigi-70 {
@apply text-vigi-70 bg-vigi-70;
}
.color-vigi-75 {
@apply text-vigi-75 bg-vigi-75;
}
.color-vigi-80 {
@apply text-vigi-80 bg-vigi-80;
}
.color-vigi-85 {
@apply text-vigi-85 bg-vigi-85;
}
.color-vigi-90 {
@apply text-vigi-90 bg-vigi-90;
}
.color-vigi-95 {
@apply text-vigi-95 bg-vigi-95;
}
.color-vigi-100 {
@apply text-vigi-100 bg-vigi-100;
}
/* End Theme Classes */
/* End theme */
/* Components */
body { body {
@apply bg-vigi-90 text-vigi-10 cursor-default; @apply bg-vigi-90 text-vigi-10 cursor-default;
user-select: none; user-select: none;
} }
.common-window { .common-window {
@apply p-3 gap-3 w-screen h-screen; @apply p-3 gap-3 w-screen h-screen;
@apply flex; @apply flex;
@apply ease-out duration-100; @apply ease-out duration-100;
} }
.common-window.collapsed { .common-window.collapsed {
@apply gap-0; @apply gap-0;
} }
.main-window { .main-window {
@apply grow flex flex-col gap-3; @apply grow flex flex-col gap-3;
} }
.browser-window { .browser-window {
@apply grow shadow-inner overflow-auto select-text cursor-auto; @apply grow overflow-auto select-text cursor-auto;
} }
.window-controls { .window-controls {
@apply flex justify-start; @apply flex justify-start;
} }
.button { .button {
@apply p-1 rounded-lg; @apply p-1 rounded-lg;
@apply ease-out duration-150; @apply ease-out duration-150;
@apply hover:bg-vigi-90; @apply hover:bg-vigi-90;
@apply hover:px-2 hover:mx-1 hover:scale-125 cursor-pointer; @apply hover:px-2 hover:mx-1 hover:scale-125 cursor-pointer;
@apply active:bg-vigi-100; @apply active:bg-vigi-100;
} }
.tabs-category { .tabs-category {
@apply flex justify-between mt-2 mx-2; @apply flex justify-between mt-2 mx-2;
} }
.block { .block {
@apply p-2 rounded-xl bg-vigi-60; @apply p-2 rounded-xl bg-vigi-60;
} }
.sidebar { .sidebar {
@apply shrink-0 grow-0 flex flex-col w-1/5; @apply shrink-0 grow-0 flex flex-col w-1/5;
@apply ease-out duration-100; @apply ease-out duration-300;
} }
.sidebar.collapsed { .sidebar.collapsed {
@apply basis-0; @apply basis-0;
@apply p-0 m-0 bg-transparent; @apply p-0 m-0;
@apply overflow-hidden;
} }
.top-bar { .top-bar {
@apply flex; @apply flex;
} }
.search-input { .search-input {
@apply ms-2 px-2 py-1 rounded-xl grow; @apply ms-2 px-2 py-1 rounded-xl grow;
@apply bg-vigi-60 outline-none; @apply bg-vigi-60 outline-none;
@apply focus:bg-vigi-50 focus:text-vigi-0 hover:bg-vigi-55; @apply focus:bg-vigi-50 focus:text-vigi-0 hover:bg-vigi-55;
@apply ease-out duration-100; @apply ease-out duration-100;
} }
input::placeholder { input::placeholder {
@apply text-vigi-40 focus:text-vigi-20; @apply text-vigi-40 focus:text-vigi-20;
} }
.tabs { .tabs {
@apply flex flex-col gap-1 mt-2 grow overflow-auto; @apply flex flex-col-reverse gap-1 mt-2 grow overflow-auto justify-end;
} }
.tab { .tab {
@apply p-2 rounded-xl bg-vigi-50; @apply p-2 rounded-xl bg-vigi-50;
@apply cursor-pointer; @apply cursor-pointer;
@apply ease-out duration-100; @apply ease-out duration-100;
@apply hover:bg-vigi-55; @apply hover:bg-vigi-55;
@apply hover:px-4; @apply hover:px-4;
@apply flex items-center gap-2 w-full truncate; @apply flex items-center gap-2 w-full truncate;
} }
.close-button { .close-button {
@apply p-1 rounded-lg; @apply p-1 rounded-lg;
@apply ease-out duration-100; @apply ease-out duration-100;
@apply hover:bg-vigi-90 active:bg-vigi-100; @apply hover:bg-vigi-90 active:bg-vigi-100;
} }
/* .tab .close-button { /* .tab .close-button {
@ -116,33 +202,33 @@ input::placeholder {
} */ } */
.tab.active { .tab.active {
@apply bg-vigi-40 text-vigi-0 font-bold; @apply bg-vigi-40 text-vigi-0 font-bold;
@apply hover:bg-vigi-45; @apply hover:bg-vigi-45;
} }
::selection { ::selection {
@apply bg-vigi-60; @apply bg-vigi-60;
} }
/* width */ /* width */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 15px; width: 15px;
} }
/* Track */ /* Track */
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
@apply bg-transparent; @apply bg-transparent;
} }
/* Handle */ /* Handle */
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
@apply rounded-xl bg-vigi-70 bg-clip-content; @apply rounded-xl bg-vigi-70 bg-clip-content;
border: 6px solid transparent; border: 6px solid transparent;
} }
/* Handle on hover */ /* Handle on hover */
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
@apply bg-vigi-75; @apply bg-vigi-75;
border: 5px solid transparent; border: 5px solid transparent;
} }

View file

@ -30,13 +30,11 @@
</script> </script>
<Block className="browser-window"> <Block className="browser-window">
<div> {#if loading}
{#if loading} <div transition:slide>
<div transition:slide> <GooLoadSpin />
<GooLoadSpin /> </div>
</div> {/if}
{/if}
<Renderer {data} /> <Renderer {data} />
</div>
</Block> </Block>

View file

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

View file

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

View file

@ -1,64 +1,65 @@
<script lang="ts"> <script lang="ts">
import ArrowLeft from "$lib/icons/ArrowLeft.svelte"; import ArrowLeft from "$lib/icons/ArrowLeft.svelte";
import ArrowRight from "$lib/icons/ArrowRight.svelte"; import ArrowRight from "$lib/icons/ArrowRight.svelte";
import Reload from "$lib/icons/Reload.svelte"; import Reload from "$lib/icons/Reload.svelte";
import SidebarLeft from "$lib/icons/SidebarLeft.svelte"; import SidebarLeft from "$lib/icons/SidebarLeft.svelte";
import SidebarRight from "$lib/icons/SidebarRight.svelte"; import SidebarRight from "$lib/icons/SidebarRight.svelte";
import { state } from "$lib/stores"; import { state } from "$lib/stores";
import { updateInput } from "$lib/utils"; import { updateInput } from "$lib/utils";
import Block from "./Block.svelte"; import Block from "./Block.svelte";
import Button from "./Button.svelte"; import Button from "./Button.svelte";
export let onBack = () => {}; export let onBack = () => {};
export let onForward = () => {}; export let onForward = () => {};
export let sidebarOpen = true; export let sidebarOpen = true;
let currentInput = ""; let currentInput = "";
let input = ""; let input = "";
state.subscribe((val) => { state.subscribe((val) => {
input = val.top_bar_input; input = val.top_bar_input;
currentInput = decodeURIComponent(input); currentInput = decodeURIComponent(input);
}); });
let iEl: HTMLInputElement; let iEl: HTMLInputElement;
</script> </script>
<div class="top-bar"> <div class="top-bar">
<Block className="flex"> <Block className="flex">
<Button onClick={() => (sidebarOpen = !sidebarOpen)}> <Button onClick={() => (sidebarOpen = !sidebarOpen)}>
{#if sidebarOpen} {#if sidebarOpen}
<SidebarLeft /> <SidebarLeft />
{:else} {:else}
<SidebarRight /> <SidebarRight />
{/if} {/if}
</Button> </Button>
<Button onClick={onBack}><ArrowLeft /></Button> <Button onClick={onBack}><ArrowLeft /></Button>
<Button onClick={onForward}><ArrowRight /></Button> <Button onClick={onForward}><ArrowRight /></Button>
<Button onClick={() => updateInput(input)}><Reload /></Button> <Button onClick={() => updateInput(input)}><Reload /></Button>
</Block> </Block>
<input <input
type="text" type="text"
placeholder="Search or enter URL" placeholder="Search or enter URL"
class="search-input" class="search-input"
bind:value={currentInput} bind:value={currentInput}
bind:this={iEl} bind:this={iEl}
on:keypress={(e) => { on:keypress={(e) => {
if (e.key === "Enter") { if (e.key === "Enter") {
updateInput(currentInput); updateInput(currentInput);
} iEl.blur();
}} }
on:focus={() => { }}
currentInput = input; on:focus={() => {
setTimeout(() => { currentInput = input;
iEl.select(); setTimeout(() => {
iEl.scrollLeft = iEl.scrollWidth; iEl.select();
}, 1); iEl.scrollLeft = iEl.scrollWidth;
}} }, 1);
on:focusout={() => { }}
currentInput = decodeURIComponent(input); on:focusout={() => {
}} currentInput = decodeURIComponent(input);
/> }}
/>
</div> </div>

View file

@ -7,7 +7,7 @@ export async function updateVigiState() {
let st = await invoke("get_js_state"); let st = await invoke("get_js_state");
state.set(st as VigiState); state.set(st as VigiState);
} catch (e) { } catch (e) {
console.log(e); writeError(e);
} }
} }
@ -16,10 +16,10 @@ export async function updateInput(input: string) {
try { try {
await invoke("update_input", { input }); await invoke("update_input", { input });
} catch (e) {
console.log(e);
} finally {
await updateVigiState(); await updateVigiState();
} catch (e) {
writeError(e, input);
} finally {
isLoading.set(false); isLoading.set(false);
} }
} }
@ -45,8 +45,22 @@ export async function removeTab(index: number) {
export async function loadTab() { export async function loadTab() {
isLoading.set(true); isLoading.set(true);
await invoke("load_tab"); try {
await updateVigiState(); await invoke("load_tab");
await updateVigiState();
isLoading.set(false); } catch (e) {
writeError(e);
} finally {
isLoading.set(false);
}
}
function writeError(e: unknown, input?: string) {
state.update((st) => {
st.current_data = [{ id: 0, body: `Error: ${e}`, argument: null }];
if (input) st.top_bar_input = input;
return st;
});
} }

View file

@ -27,7 +27,7 @@
) { ) {
return; return;
} }
if (e.key === "q") sidebarOpen = !sidebarOpen; if (e.code === "KeyQ") sidebarOpen = !sidebarOpen;
}); });
</script> </script>

63
src/theme-classes.css Normal file
View file

@ -0,0 +1,63 @@
.color-vigi-0 {
@apply text-vigi-0 bg-vigi-0;
}
.color-vigi-5 {
@apply text-vigi-5 bg-vigi-5;
}
.color-vigi-10 {
@apply text-vigi-10 bg-vigi-10;
}
.color-vigi-15 {
@apply text-vigi-15 bg-vigi-15;
}
.color-vigi-20 {
@apply text-vigi-20 bg-vigi-20;
}
.color-vigi-25 {
@apply text-vigi-25 bg-vigi-25;
}
.color-vigi-30 {
@apply text-vigi-30 bg-vigi-30;
}
.color-vigi-35 {
@apply text-vigi-35 bg-vigi-35;
}
.color-vigi-40 {
@apply text-vigi-40 bg-vigi-40;
}
.color-vigi-45 {
@apply text-vigi-45 bg-vigi-45;
}
.color-vigi-50 {
@apply text-vigi-50 bg-vigi-50;
}
.color-vigi-55 {
@apply text-vigi-55 bg-vigi-55;
}
.color-vigi-60 {
@apply text-vigi-60 bg-vigi-60;
}
.color-vigi-65 {
@apply text-vigi-65 bg-vigi-65;
}
.color-vigi-70 {
@apply text-vigi-70 bg-vigi-70;
}
.color-vigi-75 {
@apply text-vigi-75 bg-vigi-75;
}
.color-vigi-80 {
@apply text-vigi-80 bg-vigi-80;
}
.color-vigi-85 {
@apply text-vigi-85 bg-vigi-85;
}
.color-vigi-90 {
@apply text-vigi-90 bg-vigi-90;
}
.color-vigi-95 {
@apply text-vigi-95 bg-vigi-95;
}
.color-vigi-100 {
@apply text-vigi-100 bg-vigi-100;
}

View file

@ -1,7 +1,12 @@
let colors = {}; let bgColors = {};
let textColors = {};
for (let i = 0; i <= 100; i += 5) { for (let i = 0; i <= 100; i += 5) {
colors[`vigi-${i}`] = `color-mix(in hsl, var(--max) ${i}%, var(--min))`; bgColors[`vigi-${i}`] =
`color-mix(in oklch, var(--max-bg) ${i}%, var(--min-bg))`;
textColors[`vigi-${i}`] =
`color-mix(in oklch, var(--max-text) ${i}%, var(--min-text))`;
} }
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
@ -9,8 +14,8 @@ export default {
content: ["./src/**/*.{html,js,svelte,ts}"], content: ["./src/**/*.{html,js,svelte,ts}"],
theme: { theme: {
extend: { extend: {
colors, colors: bgColors,
textColor: colors, textColor: textColors,
}, },
}, },
plugins: [], plugins: [],