mirror of
https://github.com/nekename/OpenDeck.git
synced 2026-10-28 09:44:01 +00:00
Implement dark theme
This commit is contained in:
1 parent
23538d2004
commit
03807b09ff
21 files changed
+114
-64
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 84 KiB |
@@ -27,6 +27,7 @@ OpenDeck supports ProntoKey and Elgato Stream Deck hardware on all three major d
|
||||
|
||||
## Showcase
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
@@ -54,6 +54,7 @@ where
|
||||
pub struct Settings {
|
||||
pub language: String,
|
||||
pub autolaunch: bool,
|
||||
pub darktheme: bool
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
@@ -61,6 +62,7 @@ impl Default for Settings {
|
||||
Self {
|
||||
language: "en".to_owned(),
|
||||
autolaunch: false,
|
||||
darktheme: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
@@ -1,3 +1,25 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
select {
|
||||
@apply
|
||||
appearance-none
|
||||
px-2 py-1
|
||||
text-sm text-neutral-700 dark:text-neutral-300
|
||||
bg-neutral-100 dark:bg-neutral-700
|
||||
border-2 dark:border-neutral-900 outline-none
|
||||
cursor-pointer
|
||||
}
|
||||
|
||||
.select-wrapper {
|
||||
@apply relative
|
||||
}
|
||||
|
||||
.select-wrapper::after {
|
||||
@apply
|
||||
absolute right-4 top-[47.5%] -translate-y-1/2
|
||||
w-2 h-2 rotate-45
|
||||
border-r-2 border-b-2
|
||||
pointer-events-none content-['_']
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<div class="grow mt-1 overflow-auto">
|
||||
{#each Object.entries(categories) as [ name, actions ]}
|
||||
<h3 class="text-xl font-semibold"> {name} </h3>
|
||||
<h3 class="text-xl font-semibold dark:text-neutral-300"> {name} </h3>
|
||||
{#each actions as action}
|
||||
{#if action.visible_in_action_list}
|
||||
<ListedAction {action} localisation={localiseAction(action, $localisations)} />
|
||||
|
||||
@@ -28,10 +28,12 @@
|
||||
listen("devices", ({ payload }: { payload: { [id: string]: DeviceInfo }}) => devices = payload);
|
||||
</script>
|
||||
|
||||
<select bind:value class="w-full">
|
||||
<option value="" disabled selected> Choose a device... </option>
|
||||
<div class="select-wrapper">
|
||||
<select bind:value class="w-full">
|
||||
<option value="" disabled selected> Choose a device... </option>
|
||||
|
||||
{#each Object.entries(devices).sort() as [ id, device ]}
|
||||
<option value={id}> {device.name} </option>
|
||||
{/each}
|
||||
</select>
|
||||
{#each Object.entries(devices).sort() as [ id, device ]}
|
||||
<option value={id}> {device.name} </option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
@@ -90,7 +90,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="relative m-2 border-2 rounded-md select-none"
|
||||
class="relative m-2 border-2 dark:border-neutral-700 rounded-md select-none"
|
||||
style="width: calc(8rem * {scale}); height: calc(8rem * {scale});"
|
||||
on:dragover on:drop
|
||||
draggable on:dragstart
|
||||
|
||||
@@ -17,5 +17,5 @@
|
||||
draggable
|
||||
on:dragstart={handleDragStart}
|
||||
/>
|
||||
<span> {localisation.name} </span>
|
||||
<span class="dark:text-neutral-400"> {localisation.name} </span>
|
||||
</div>
|
||||
@@ -44,16 +44,16 @@
|
||||
context = null!;
|
||||
</script>
|
||||
|
||||
<div class="px-6 pt-6 pb-4">
|
||||
<div class="px-6 pt-6 pb-4 dark:text-neutral-300">
|
||||
<button class="float-right text-xl" on:click={() => $inspectedMultiAction = null}> ✕ </button>
|
||||
<h1 class="font-semibold text-2xl"> Multi Action </h1>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col h-80 overflow-scroll">
|
||||
{#each slot as instance, index}
|
||||
<div class="flex flex-row items-center mx-4 my-1 bg-gray-100 rounded-md">
|
||||
<div class="flex flex-row items-center mx-4 my-1 bg-neutral-100 dark:bg-neutral-900 rounded-md">
|
||||
<Key slot={[instance]} {context} active={false} scale={3/4} />
|
||||
<p class="ml-4 text-xl"> {instance.action.name} </p>
|
||||
<p class="ml-4 text-xl dark:text-neutral-400"> {instance.action.name} </p>
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<img
|
||||
src="/rubbish.png"
|
||||
@@ -64,11 +64,11 @@
|
||||
</div>
|
||||
{/each}
|
||||
<div
|
||||
class="flex flex-row items-center mx-4 mt-1 mb-4 bg-gray-100 border-2 border-dashed rounded-md"
|
||||
class="flex flex-row items-center mx-4 mt-1 mb-4 bg-neutral-100 dark:bg-neutral-900 border-2 border-dashed dark:border-neutral-700 rounded-md"
|
||||
on:dragover={handleDragOver} on:drop={handleDrop}
|
||||
role="cell" tabindex="-1"
|
||||
>
|
||||
<img src="/cube.png" class="m-2 w-24 rounded-xl" alt="Add new action" />
|
||||
<p class="ml-4 text-xl text-gray-500"> Drop actions here </p>
|
||||
<p class="ml-4 text-xl text-neutral-500"> Drop actions here </p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,22 +40,22 @@
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="mt-2 p-1 w-1/2 text-sm text-gray-700 bg-gray-100 border rounded-lg"
|
||||
class="mt-2 p-1 w-1/2 text-sm text-neutral-700 dark:text-neutral-300 bg-neutral-100 dark:bg-neutral-700 border dark:border-neutral-600 rounded-lg"
|
||||
on:click={() => showPopup = true}
|
||||
>
|
||||
Plugins
|
||||
</button>
|
||||
|
||||
<Popup show={showPopup}>
|
||||
<button class="mr-2 my-1 float-right text-xl" on:click={() => showPopup = false}> ✕ </button>
|
||||
<h2 class="m-2 font-semibold text-xl"> Manage plugins </h2>
|
||||
<button class="mr-2 my-1 float-right text-xl dark:text-neutral-300" on:click={() => showPopup = false}> ✕ </button>
|
||||
<h2 class="m-2 font-semibold text-xl dark:text-neutral-300"> Manage plugins </h2>
|
||||
|
||||
<h2 class="mx-2 mt-6 mb-2 text-lg"> Installed plugins </h2>
|
||||
<h2 class="mx-2 mt-6 mb-2 text-lg dark:text-neutral-400"> Installed plugins </h2>
|
||||
<div class="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||
{#each plugins as plugin}
|
||||
<div class="flex flex-row items-center m-2 p-2 bg-gray-200 rounded-md">
|
||||
<div class="flex flex-row items-center m-2 p-2 bg-neutral-200 dark:bg-neutral-700 rounded-md">
|
||||
<img src={"http://localhost:57118/" + plugin.icon} class="w-24 rounded-md" alt={plugin.name} />
|
||||
<div class="ml-4 mr-2">
|
||||
<div class="ml-4 mr-2 dark:text-neutral-300">
|
||||
<p>
|
||||
<span class="font-semibold">
|
||||
{($localisations && $localisations[plugin.id] && $localisations[plugin.id].Name) ? $localisations[plugin.id].Name : plugin.name}
|
||||
@@ -77,14 +77,14 @@
|
||||
</div>
|
||||
|
||||
{#await fetch("https://plugins.amansprojects.com/catalogue.json")}
|
||||
<h2 class="mx-2 mt-6 mb-2 text-md"> Loading plugin list... </h2>
|
||||
<h2 class="mx-2 mt-6 mb-2 text-md dark:text-neutral-400"> Loading plugin list... </h2>
|
||||
{:then res}
|
||||
{#await res.json() then entries}
|
||||
<h2 class="mx-2 mt-6 mb-2 text-lg"> Plugin store </h2>
|
||||
<h2 class="mx-2 mt-6 mb-2 text-lg dark:text-neutral-400"> Plugin store </h2>
|
||||
<div class="flex flex-row m-2">
|
||||
<input
|
||||
bind:value={search}
|
||||
class="grow p-2 rounded-md outline-none"
|
||||
class="grow p-2 dark:text-neutral-300 dark:bg-neutral-700 rounded-md outline-none"
|
||||
placeholder="Search plugins"
|
||||
type="search"
|
||||
spellcheck="false"
|
||||
@@ -93,11 +93,11 @@
|
||||
<div class="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||
{#each entries as plugin}
|
||||
<div
|
||||
class="flex flex-row items-center m-2 p-2 bg-gray-200 rounded-md"
|
||||
class="flex flex-row items-center m-2 p-2 bg-neutral-200 dark:bg-neutral-700 rounded-md"
|
||||
class:hidden={!plugin.name.toUpperCase().includes(search.toUpperCase())}
|
||||
>
|
||||
<img src="https://plugins.amansprojects.com/icons/{plugin.id}.png" class="w-24 rounded-md" alt={plugin.name} />
|
||||
<div class="ml-4 mr-2">
|
||||
<div class="ml-4 mr-2 dark:text-neutral-300">
|
||||
<p class="font-semibold"> {plugin.name} </p>
|
||||
{plugin.author}
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
<div class="absolute top-0 left-0 m-2 p-4 w-[calc(100%-1rem)] h-[calc(100%-1rem)] bg-gray-100 border-2 rounded-lg overflow-scroll">
|
||||
<div class="absolute top-0 left-0 m-2 p-4 w-[calc(100%-1rem)] h-[calc(100%-1rem)] bg-neutral-100 dark:bg-neutral-800 border-2 dark:border-neutral-700 rounded-lg overflow-scroll z-30">
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
@@ -55,20 +55,22 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<select bind:value class="mt-1 w-full">
|
||||
{#each profiles as profile}
|
||||
<option value={profile}> {profile} </option>
|
||||
{/each}
|
||||
<option value="opendeck_edit_profiles"> Edit... </option>
|
||||
</select>
|
||||
<div class="select-wrapper">
|
||||
<select bind:value class="mt-1 w-full">
|
||||
{#each profiles as profile}
|
||||
<option value={profile}> {profile} </option>
|
||||
{/each}
|
||||
<option value="opendeck_edit_profiles"> Edit... </option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<Popup show={showPopup}>
|
||||
<button class="mr-1 float-right text-xl" on:click={() => showPopup = false}> ✕ </button>
|
||||
<h2 class="text-xl font-semibold"> {device.name} </h2>
|
||||
<button class="mr-1 float-right text-xl dark:text-neutral-300" on:click={() => showPopup = false}> ✕ </button>
|
||||
<h2 class="text-xl font-semibold dark:text-neutral-300"> {device.name} </h2>
|
||||
|
||||
<div class="flex flex-row mt-2 mb-1">
|
||||
<input class="grow p-2 rounded-l-md outline-none" placeholder="Profile name" bind:value={nameInput} />
|
||||
<button class="px-4 bg-gray-200 rounded-r-md" on:click={async () => {
|
||||
<input class="grow p-2 dark:text-neutral-300 dark:bg-neutral-700 rounded-l-md outline-none" placeholder="Profile name" bind:value={nameInput} />
|
||||
<button class="px-4 dark:text-neutral-300 bg-neutral-200 dark:bg-neutral-900 rounded-r-md" on:click={async () => {
|
||||
await setProfile(nameInput);
|
||||
value = nameInput;
|
||||
nameInput = "";
|
||||
@@ -77,10 +79,10 @@
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 divide-y">
|
||||
{#each profiles as profile, i}
|
||||
{#each profiles as profile}
|
||||
<div class="pt-2">
|
||||
<input type="radio" bind:group={value} value={profile} />
|
||||
{profile}
|
||||
<span class="dark:text-neutral-400"> {profile} </span>
|
||||
{#if profile != value}
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<img
|
||||
|
||||
@@ -98,11 +98,11 @@
|
||||
$: instances = profile.keys.reduce((prev, current) => prev.concat(current), []).concat(profile.sliders.reduce((prev, current) => prev.concat(current), []));
|
||||
</script>
|
||||
|
||||
<div class="grow overflow-scroll bg-white border-t" bind:this={iframeContainer}>
|
||||
<div class="grow overflow-scroll bg-white dark:bg-neutral-900 border-t dark:border-neutral-700 z-20" bind:this={iframeContainer}>
|
||||
<button
|
||||
bind:this={iframeClosePopup}
|
||||
on:click={() => closePopup(iframePopupsOpen[iframePopupsOpen.length - 1])}
|
||||
class="absolute top-2 right-2 text-2xl font-bold hidden"
|
||||
class="absolute top-2 right-2 text-2xl dark:text-neutral-300 font-bold hidden"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
@@ -6,30 +6,44 @@
|
||||
import Tooltip from "./Tooltip.svelte";
|
||||
|
||||
let showPopup = false;
|
||||
|
||||
settings.subscribe((settings) => {
|
||||
if (settings) updateTheme(settings.darktheme);
|
||||
});
|
||||
|
||||
function updateTheme(darktheme: boolean) {
|
||||
if (darktheme) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="ml-2 mt-2 p-1 w-1/2 text-sm text-gray-700 bg-gray-100 border rounded-lg"
|
||||
class="ml-2 mt-2 p-1 w-1/2 text-sm text-neutral-700 dark:text-neutral-300 bg-neutral-100 dark:bg-neutral-700 border dark:border-neutral-600 rounded-lg"
|
||||
on:click={() => showPopup = true}
|
||||
>
|
||||
Settings
|
||||
</button>
|
||||
|
||||
<Popup show={showPopup}>
|
||||
<button class="mr-2 my-1 float-right text-xl" on:click={() => showPopup = false}> ✕ </button>
|
||||
<h2 class="m-2 font-semibold text-xl"> Settings </h2>
|
||||
<button class="mr-2 my-1 float-right text-xl dark:text-neutral-300" on:click={() => showPopup = false}> ✕ </button>
|
||||
<h2 class="m-2 font-semibold text-xl dark:text-neutral-300"> Settings </h2>
|
||||
{#if $settings}
|
||||
<div class="flex flex-row items-center m-2 space-x-2">
|
||||
<span> Language: </span>
|
||||
<select bind:value={$settings.language}>
|
||||
<option value="en"> English </option>
|
||||
<option value="es"> Español </option>
|
||||
<option value="zh_CN"> 中文 </option>
|
||||
<option value="fr"> Français </option>
|
||||
<option value="de"> Deutsch </option>
|
||||
<option value="ja"> 日本語 </option>
|
||||
<option value="ko"> 韓国語 </option>
|
||||
</select>
|
||||
<span class="dark:text-neutral-400"> Language: </span>
|
||||
<div class="select-wrapper">
|
||||
<select bind:value={$settings.language} class="w-32">
|
||||
<option value="en"> English </option>
|
||||
<option value="es"> Español </option>
|
||||
<option value="zh_CN"> 中文 </option>
|
||||
<option value="fr"> Français </option>
|
||||
<option value="de"> Deutsch </option>
|
||||
<option value="ja"> 日本語 </option>
|
||||
<option value="ko"> 韓国語 </option>
|
||||
</select>
|
||||
</div>
|
||||
<Tooltip>
|
||||
OpenDeck itself is not yet translated.
|
||||
Changing this setting will translate the text from installed plugins into your language for those that support it.
|
||||
@@ -37,13 +51,18 @@
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center m-2 space-x-2">
|
||||
<span> Autolaunch: </span>
|
||||
<span class="dark:text-neutral-400"> Autolaunch: </span>
|
||||
<input type="checkbox" bind:checked={$settings.autolaunch} />
|
||||
<Tooltip> If this option is enabled, OpenDeck will automatically start at login. </Tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center m-2 space-x-2">
|
||||
<span class="dark:text-neutral-400"> Dark theme: </span>
|
||||
<input type="checkbox" bind:checked={$settings.darktheme} />
|
||||
</div>
|
||||
{/if}
|
||||
<button
|
||||
class="ml-2 mt-2 px-2 py-1 text-sm text-gray-700 bg-gray-100 border rounded-lg"
|
||||
class="ml-2 mt-2 px-2 py-1 text-sm text-neutral-700 dark:text-neutral-300 bg-neutral-100 dark:bg-neutral-700 border dark:border-neutral-600 rounded-lg"
|
||||
on:click={() => invoke("open_config_directory")}
|
||||
>
|
||||
Open config directory
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="relative flex items-center m-2 w-20 h-144 border-2 rounded-md select-none"
|
||||
class="relative flex items-center m-2 w-20 h-144 border-2 dark:border-neutral-700 rounded-md select-none"
|
||||
on:dragover on:drop
|
||||
draggable on:dragstart
|
||||
role="cell" tabindex="-1"
|
||||
@@ -94,7 +94,7 @@
|
||||
<img
|
||||
src="/alert.png"
|
||||
alt="Alert"
|
||||
class="absolute top-0 left-0 p-1 w-full aspect-square top-[50%] -translate-y-1/2 transition-opacity duration-1000"
|
||||
class="absolute left-0 p-1 w-full aspect-square top-[50%] -translate-y-1/2 transition-opacity duration-1000"
|
||||
class:opacity-0={showAlert == 2}
|
||||
/>
|
||||
{/if}
|
||||
@@ -102,7 +102,7 @@
|
||||
<img
|
||||
src="/ok.png"
|
||||
alt="OK"
|
||||
class="absolute top-0 left-0 p-1 w-full aspect-square top-[50%] -translate-y-1/2 transition-opacity duration-1000"
|
||||
class="absolute left-0 p-1 w-full aspect-square top-[50%] -translate-y-1/2 transition-opacity duration-1000"
|
||||
class:opacity-0={showOk == 2}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
>
|
||||
<img src="/question.png" class="w-6" alt="Help" />
|
||||
{#if show}
|
||||
<div class="absolute mt-2 p-2 w-96 text-xs bg-gray-100 border-2 rounded-lg">
|
||||
<div class="absolute mt-2 p-2 w-96 text-xs dark:text-neutral-300 bg-neutral-100 dark:bg-neutral-700 border-2 dark:border-neutral-600 rounded-lg">
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
export type Settings = {
|
||||
language: string,
|
||||
autolaunch: boolean
|
||||
autolaunch: boolean,
|
||||
darktheme: boolean
|
||||
};
|
||||
|
||||
import { invoke } from "@tauri-apps/api";
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
import "../app.css";
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row h-screen">
|
||||
<div class="flex flex-row h-screen dark:bg-neutral-900">
|
||||
<slot />
|
||||
</div>
|
||||
@@ -34,7 +34,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col p-2 grow max-w-[18rem] h-full border-l">
|
||||
<div class="flex flex-col p-2 grow max-w-[18rem] h-full border-l dark:border-neutral-700">
|
||||
{#if !$inspectedMultiAction}
|
||||
<DeviceSelector bind:device={selectedDevice} />
|
||||
{#if selectedDevice}
|
||||
@@ -42,7 +42,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
<ActionList bind:this={actionList} />
|
||||
<hr class="mt-2 border" />
|
||||
<hr class="mt-2 border dark:border-neutral-700" />
|
||||
<div class="flex flex-row">
|
||||
<PluginManager {actionList} />
|
||||
<SettingsView />
|
||||
|
||||
+2
-1
@@ -4,5 +4,6 @@ export default {
|
||||
theme: {
|
||||
extend: {}
|
||||
},
|
||||
plugins: []
|
||||
plugins: [],
|
||||
darkMode: "selector"
|
||||
}
|
||||
Reference in new issue
Block a user