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: ""
with:
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."
releaseDraft: true
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 {
todo!();
Err(VigiError::Parse)?
}
};

View file

@ -2,109 +2,195 @@
@tailwind components;
@tailwind utilities;
:root {
--min: #96e28a;
--max: #193815;
/* Theme */
/* --min: #8a9fe2;
--max: #151a38; */
:root {
/* 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 {
@apply bg-vigi-90 text-vigi-10 cursor-default;
user-select: none;
@apply bg-vigi-90 text-vigi-10 cursor-default;
user-select: none;
}
.common-window {
@apply p-3 gap-3 w-screen h-screen;
@apply flex;
@apply p-3 gap-3 w-screen h-screen;
@apply flex;
@apply ease-out duration-100;
@apply ease-out duration-100;
}
.common-window.collapsed {
@apply gap-0;
@apply gap-0;
}
.main-window {
@apply grow flex flex-col gap-3;
@apply grow flex flex-col gap-3;
}
.browser-window {
@apply grow shadow-inner overflow-auto select-text cursor-auto;
@apply grow overflow-auto select-text cursor-auto;
}
.window-controls {
@apply flex justify-start;
@apply flex justify-start;
}
.button {
@apply p-1 rounded-lg;
@apply ease-out duration-150;
@apply p-1 rounded-lg;
@apply ease-out duration-150;
@apply hover:bg-vigi-90;
@apply hover:px-2 hover:mx-1 hover:scale-125 cursor-pointer;
@apply hover:bg-vigi-90;
@apply hover:px-2 hover:mx-1 hover:scale-125 cursor-pointer;
@apply active:bg-vigi-100;
@apply active:bg-vigi-100;
}
.tabs-category {
@apply flex justify-between mt-2 mx-2;
@apply flex justify-between mt-2 mx-2;
}
.block {
@apply p-2 rounded-xl bg-vigi-60;
@apply p-2 rounded-xl bg-vigi-60;
}
.sidebar {
@apply shrink-0 grow-0 flex flex-col w-1/5;
@apply ease-out duration-100;
@apply shrink-0 grow-0 flex flex-col w-1/5;
@apply ease-out duration-300;
}
.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 {
@apply flex;
@apply flex;
}
.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 focus:bg-vigi-50 focus:text-vigi-0 hover:bg-vigi-55;
@apply bg-vigi-60 outline-none;
@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 {
@apply text-vigi-40 focus:text-vigi-20;
@apply text-vigi-40 focus:text-vigi-20;
}
.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 {
@apply p-2 rounded-xl bg-vigi-50;
@apply cursor-pointer;
@apply ease-out duration-100;
@apply p-2 rounded-xl bg-vigi-50;
@apply cursor-pointer;
@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 {
@apply p-1 rounded-lg;
@apply ease-out duration-100;
@apply p-1 rounded-lg;
@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 {
@ -116,33 +202,33 @@ input::placeholder {
} */
.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 {
@apply bg-vigi-60;
@apply bg-vigi-60;
}
/* width */
::-webkit-scrollbar {
width: 15px;
width: 15px;
}
/* Track */
::-webkit-scrollbar-track {
@apply bg-transparent;
@apply bg-transparent;
}
/* Handle */
::-webkit-scrollbar-thumb {
@apply rounded-xl bg-vigi-70 bg-clip-content;
border: 6px solid transparent;
@apply rounded-xl bg-vigi-70 bg-clip-content;
border: 6px solid transparent;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
@apply bg-vigi-75;
border: 5px solid transparent;
@apply bg-vigi-75;
border: 5px solid transparent;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@ export async function updateVigiState() {
let st = await invoke("get_js_state");
state.set(st as VigiState);
} catch (e) {
console.log(e);
writeError(e);
}
}
@ -16,10 +16,10 @@ export async function updateInput(input: string) {
try {
await invoke("update_input", { input });
} catch (e) {
console.log(e);
} finally {
await updateVigiState();
} catch (e) {
writeError(e, input);
} finally {
isLoading.set(false);
}
}
@ -45,8 +45,22 @@ export async function removeTab(index: number) {
export async function loadTab() {
isLoading.set(true);
await invoke("load_tab");
await updateVigiState();
isLoading.set(false);
try {
await invoke("load_tab");
await updateVigiState();
} 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;
}
if (e.key === "q") sidebarOpen = !sidebarOpen;
if (e.code === "KeyQ") sidebarOpen = !sidebarOpen;
});
</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) {
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} */
@ -9,8 +14,8 @@ export default {
content: ["./src/**/*.{html,js,svelte,ts}"],
theme: {
extend: {
colors,
textColor: colors,
colors: bgColors,
textColor: textColors,
},
},
plugins: [],