refactor: fix casing and spacing in settings.scss

refactor: improve keybind saving logic and error handling
fix: update keybind references to settings in app and tray setup
fix: back button not working on settings
This commit is contained in:
PandaDEV 2025-01-02 14:54:42 +10:00
parent b328b8fa9c
commit 25f7b116f6
No known key found for this signature in database
GPG key ID: 13EFF9BAF70EE75C
3 changed files with 237 additions and 74 deletions

33
app.vue
View file

@ -1,25 +1,28 @@
<template> <template>
<div style="pointer-events: auto;"> <div style="pointer-events: auto">
<NuxtPage /> <NuxtPage />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { listen } from '@tauri-apps/api/event' import { listen } from "@tauri-apps/api/event";
import { app, window } from '@tauri-apps/api'; import { app, window } from "@tauri-apps/api";
import { onMounted } from 'vue' import { onMounted } from "vue";
const keyboard = useKeyboard();
onMounted(async () => { onMounted(async () => {
await listen('settings', async () => { await listen("settings", async () => {
await navigateTo('/settings') keyboard.unregisterAll();
await navigateTo("/settings");
await app.show(); await app.show();
await window.getCurrentWindow().show(); await window.getCurrentWindow().show();
}) });
await listen('main_route', async () => { await listen("main_route", async () => {
await navigateTo('/') await navigateTo("/");
}) });
}) });
</script> </script>
<style lang="scss"> <style lang="scss">
@ -51,7 +54,7 @@ onMounted(async () => {
margin: 0; margin: 0;
padding: 0; padding: 0;
box-sizing: border-box; box-sizing: border-box;
color: #E5DFD5; color: #e5dfd5;
text-decoration: none; text-decoration: none;
font-family: SFRoundedRegular; font-family: SFRoundedRegular;
scroll-behavior: smooth; scroll-behavior: smooth;
@ -60,9 +63,9 @@ onMounted(async () => {
position: relative; position: relative;
z-index: 1; z-index: 1;
--os-handle-bg: #ADA9A1; --os-handle-bg: #ada9a1;
--os-handle-bg-hover: #78756F; --os-handle-bg-hover: #78756f;
--os-handle-bg-active: #78756F; --os-handle-bg-active: #78756f;
} }
html, html,

View file

@ -65,10 +65,17 @@
</template> </template>
<template v-else-if="hasFavicon(item.favicon ?? '')"> <template v-else-if="hasFavicon(item.favicon ?? '')">
<img <img
:src="item.favicon ? getFaviconFromDb(item.favicon) : '../public/icons/Link.svg'" :src="
item.favicon
? getFaviconFromDb(item.favicon)
: '../public/icons/Link.svg'
"
alt="Favicon" alt="Favicon"
class="favicon" class="favicon"
@error="($event.target as HTMLImageElement).src = '../public/icons/Link.svg'" /> @error="
($event.target as HTMLImageElement).src =
'../public/icons/Link.svg'
" />
</template> </template>
<img <img
src="../public/icons/File.svg" src="../public/icons/File.svg"
@ -121,8 +128,12 @@
:src="getYoutubeThumbnail(selectedItem.content)" :src="getYoutubeThumbnail(selectedItem.content)"
alt="YouTube Thumbnail" /> alt="YouTube Thumbnail" />
</div> </div>
<div class="content" v-else-if="selectedItem?.content_type === ContentType.Link && pageOgImage"> <div
<img :src="pageOgImage" alt="Image" class="image"> class="content"
v-else-if="
selectedItem?.content_type === ContentType.Link && pageOgImage
">
<img :src="pageOgImage" alt="Image" class="image" />
</div> </div>
<OverlayScrollbarsComponent v-else class="content"> <OverlayScrollbarsComponent v-else class="content">
<span>{{ selectedItem?.content || "" }}</span> <span>{{ selectedItem?.content || "" }}</span>
@ -135,9 +146,7 @@
<div class="info-content" v-if="selectedItem && getInfo"> <div class="info-content" v-if="selectedItem && getInfo">
<div class="info-row" v-for="(row, index) in infoRows" :key="index"> <div class="info-row" v-for="(row, index) in infoRows" :key="index">
<p class="label">{{ row.label }}</p> <p class="label">{{ row.label }}</p>
<span <span :class="{ 'url-truncate': row.isUrl }" :data-text="row.value">
:class="{ 'url-truncate': row.isUrl }"
:data-text="row.value">
{{ row.value }} {{ row.value }}
</span> </span>
</div> </div>
@ -158,7 +167,15 @@ import { listen } from "@tauri-apps/api/event";
import { useNuxtApp } from "#app"; import { useNuxtApp } from "#app";
import { invoke } from "@tauri-apps/api/core"; import { invoke } from "@tauri-apps/api/core";
import { HistoryItem, ContentType } from "~/types/types"; import { HistoryItem, ContentType } from "~/types/types";
import type { InfoText, InfoImage, InfoFile, InfoLink, InfoColor, InfoCode } from "~/types/types"; import type {
InfoText,
InfoImage,
InfoFile,
InfoLink,
InfoColor,
InfoCode,
} from "~/types/types";
import { Key } from "wrdu-keyboard/key";
interface GroupedHistory { interface GroupedHistory {
label: string; label: string;
@ -188,8 +205,8 @@ const imageSizes = shallowRef<Record<string, string>>({});
const lastUpdateTime = ref<number>(Date.now()); const lastUpdateTime = ref<number>(Date.now());
const imageLoadError = ref<boolean>(false); const imageLoadError = ref<boolean>(false);
const imageLoading = ref<boolean>(false); const imageLoading = ref<boolean>(false);
const pageTitle = ref<string>(''); const pageTitle = ref<string>("");
const pageOgImage = ref<string>(''); const pageOgImage = ref<string>("");
const keyboard = useKeyboard(); const keyboard = useKeyboard();
@ -583,41 +600,35 @@ const setupEventListeners = async (): Promise<void> => {
searchInput.value?.blur(); searchInput.value?.blur();
}); });
keyboard.down("ArrowDown", (event) => { keyboard.prevent.down([Key.DownArrow], (event) => {
event.preventDefault();
selectNext(); selectNext();
}); });
keyboard.down("ArrowUp", (event) => { keyboard.prevent.down([Key.UpArrow], (event) => {
event.preventDefault();
selectPrevious(); selectPrevious();
}); });
keyboard.down("Enter", (event) => { keyboard.prevent.down([Key.Enter], (event) => {
event.preventDefault();
pasteSelectedItem(); pasteSelectedItem();
}); });
keyboard.down("Escape", (event) => { keyboard.prevent.down([Key.Escape], (event) => {
event.preventDefault();
hideApp(); hideApp();
}); });
keyboard.down("all", (event) => { switch (os.value) {
const isMacActionCombo = case "macos":
os.value === "macos" && keyboard.prevent.down([Key.LeftMeta, Key.K], (event) => {});
(event.code === "MetaLeft" || event.code === "MetaRight") &&
event.key === "k";
const isOtherOsActionCombo = keyboard.prevent.down([Key.RightMeta, Key.K], (event) => {});
os.value !== "macos" && break;
(event.code === "ControlLeft" || event.code === "ControlRight") &&
event.key === "k";
if (isMacActionCombo || isOtherOsActionCombo) { case "linux" || "windows":
event.preventDefault(); keyboard.prevent.down([Key.LeftControl, Key.K], (event) => {});
}
}); keyboard.prevent.down([Key.RightControl, Key.K], (event) => {});
break;
}
}; };
const hideApp = async (): Promise<void> => { const hideApp = async (): Promise<void> => {
@ -646,7 +657,7 @@ watch(searchQuery, () => {
onMounted(async () => { onMounted(async () => {
try { try {
os.value = await platform(); os.value = platform();
await loadHistoryChunk(); await loadHistoryChunk();
resultsContainer.value resultsContainer.value
@ -686,27 +697,33 @@ const formatFileSize = (bytes: number): string => {
const fetchPageMeta = async (url: string) => { const fetchPageMeta = async (url: string) => {
try { try {
const [title, ogImage] = await invoke('fetch_page_meta', { url }) as [string, string | null]; const [title, ogImage] = (await invoke("fetch_page_meta", { url })) as [
string,
string | null
];
pageTitle.value = title; pageTitle.value = title;
if (ogImage) { if (ogImage) {
pageOgImage.value = ogImage; pageOgImage.value = ogImage;
} }
} catch (error) { } catch (error) {
console.error('Error fetching page meta:', error); console.error("Error fetching page meta:", error);
pageTitle.value = 'Error loading title'; pageTitle.value = "Error loading title";
} }
}; };
watch(() => selectedItem.value, (newItem) => { watch(
if (newItem?.content_type === ContentType.Link) { () => selectedItem.value,
pageTitle.value = 'Loading...'; (newItem) => {
pageOgImage.value = ''; if (newItem?.content_type === ContentType.Link) {
fetchPageMeta(newItem.content); pageTitle.value = "Loading...";
} else { pageOgImage.value = "";
pageTitle.value = ''; fetchPageMeta(newItem.content);
pageOgImage.value = ''; } else {
pageTitle.value = "";
pageOgImage.value = "";
}
} }
}); );
const getInfo = computed(() => { const getInfo = computed(() => {
if (!selectedItem.value) return null; if (!selectedItem.value) return null;
@ -716,7 +733,10 @@ const getInfo = computed(() => {
copied: selectedItem.value.timestamp, copied: selectedItem.value.timestamp,
}; };
const infoMap: Record<ContentType, () => InfoText | InfoImage | InfoFile | InfoLink | InfoColor | InfoCode> = { const infoMap: Record<
ContentType,
() => InfoText | InfoImage | InfoFile | InfoLink | InfoColor | InfoCode
> = {
[ContentType.Text]: () => ({ [ContentType.Text]: () => ({
...baseInfo, ...baseInfo,
content_type: ContentType.Text, content_type: ContentType.Text,
@ -754,7 +774,8 @@ const getInfo = computed(() => {
const max = Math.max(rNorm, gNorm, bNorm); const max = Math.max(rNorm, gNorm, bNorm);
const min = Math.min(rNorm, gNorm, bNorm); const min = Math.min(rNorm, gNorm, bNorm);
let h = 0, s = 0; let h = 0,
s = 0;
const l = (max + min) / 2; const l = (max + min) / 2;
if (max !== min) { if (max !== min) {
@ -780,14 +801,16 @@ const getInfo = computed(() => {
content_type: ContentType.Color, content_type: ContentType.Color,
hex: hex, hex: hex,
rgb: `rgb(${r}, ${g}, ${b})`, rgb: `rgb(${r}, ${g}, ${b})`,
hsl: `hsl(${Math.round(h * 360)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%)`, hsl: `hsl(${Math.round(h * 360)}, ${Math.round(s * 100)}%, ${Math.round(
l * 100
)}%)`,
}; };
}, },
[ContentType.Code]: () => ({ [ContentType.Code]: () => ({
...baseInfo, ...baseInfo,
content_type: ContentType.Code, content_type: ContentType.Code,
language: selectedItem.value!.language ?? "Unknown", language: selectedItem.value!.language ?? "Unknown",
lines: selectedItem.value!.content.split('\n').length, lines: selectedItem.value!.content.split("\n").length,
}), }),
}; };
@ -799,24 +822,37 @@ const infoRows = computed(() => {
const commonRows = [ const commonRows = [
{ label: "Source", value: getInfo.value.source, isUrl: false }, { label: "Source", value: getInfo.value.source, isUrl: false },
{ label: "Content Type", value: getInfo.value.content_type.charAt(0).toUpperCase() + getInfo.value.content_type.slice(1), isUrl: false }, {
label: "Content Type",
value:
getInfo.value.content_type.charAt(0).toUpperCase() +
getInfo.value.content_type.slice(1),
isUrl: false,
},
]; ];
const typeSpecificRows: Record<ContentType, Array<{ label: string; value: string | number; isUrl?: boolean }>> = { const typeSpecificRows: Record<
ContentType,
Array<{ label: string; value: string | number; isUrl?: boolean }>
> = {
[ContentType.Text]: [ [ContentType.Text]: [
{ label: "Characters", value: (getInfo.value as InfoText).characters }, { label: "Characters", value: (getInfo.value as InfoText).characters },
{ label: "Words", value: (getInfo.value as InfoText).words }, { label: "Words", value: (getInfo.value as InfoText).words },
], ],
[ContentType.Image]: [ [ContentType.Image]: [
{ label: "Dimensions", value: (getInfo.value as InfoImage).dimensions }, { label: "Dimensions", value: (getInfo.value as InfoImage).dimensions },
{ label: "Image size", value: formatFileSize((getInfo.value as InfoImage).size) }, {
label: "Image size",
value: formatFileSize((getInfo.value as InfoImage).size),
},
], ],
[ContentType.File]: [ [ContentType.File]: [
{ label: "Path", value: (getInfo.value as InfoFile).path }, { label: "Path", value: (getInfo.value as InfoFile).path },
], ],
[ContentType.Link]: [ [ContentType.Link]: [
...((getInfo.value as InfoLink).title && (getInfo.value as InfoLink).title !== 'Loading...' ...((getInfo.value as InfoLink).title &&
? [{ label: "Title", value: (getInfo.value as InfoLink).title || '' }] (getInfo.value as InfoLink).title !== "Loading..."
? [{ label: "Title", value: (getInfo.value as InfoLink).title || "" }]
: []), : []),
{ label: "URL", value: (getInfo.value as InfoLink).url, isUrl: true }, { label: "URL", value: (getInfo.value as InfoLink).url, isUrl: true },
{ label: "Characters", value: (getInfo.value as InfoLink).characters }, { label: "Characters", value: (getInfo.value as InfoLink).characters },
@ -832,8 +868,9 @@ const infoRows = computed(() => {
], ],
}; };
const specificRows = typeSpecificRows[getInfo.value.content_type] const specificRows = typeSpecificRows[getInfo.value.content_type].filter(
.filter(row => row.value !== ""); (row) => row.value !== ""
);
return [ return [
...commonRows, ...commonRows,

View file

@ -0,0 +1,123 @@
diff --git a/node_modules/wrdu-keyboard/.DS_Store b/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..fabbd951c2d14c46fd10fa167b8836d116bc0db6
Binary files /dev/null and b/.DS_Store differ
diff --git a/dist/runtime/keyboard.d.ts b/dist/runtime/keyboard.d.ts
index aeae40f3d2bc3efd459cce04c29c21c43884154d..6131bab4895ebb3048a5225f366430d23c5f1f13 100644
--- a/dist/runtime/keyboard.d.ts
+++ b/dist/runtime/keyboard.d.ts
@@ -1,15 +1,16 @@
-import { Key } from './types/keys.js';
-import { type Plugin } from '#app';
+import { Key } from "./types/keys.js";
+import { type Plugin } from "#app";
type Handler = (event: KeyboardEvent) => void;
type Config = {
once?: boolean;
prevent?: boolean;
};
-type PublicConfig = Omit<Config, 'prevent'>;
+type PublicConfig = Omit<Config, "prevent">;
type New = (keys: Key[], handler: Handler, config?: PublicConfig) => void;
export interface Keyboard {
init: () => void;
stop: () => void;
+ unregisterAll: () => void;
down: New;
up: New;
prevent: {
diff --git a/dist/runtime/keyboard.js b/dist/runtime/keyboard.js
index e16f600258cee90d185ffc52777bed95c14bd93e..e4ce2678db649ec82e5a67fcdb74f5cdb37820aa 100644
--- a/dist/runtime/keyboard.js
+++ b/dist/runtime/keyboard.js
@@ -1,13 +1,14 @@
import { Key } from "./types/keys.js";
import { defineNuxtPlugin } from "#app";
-const getKeyString = (keys) => keys[0] == Key.All ? keys.sort().join("+") : "All";
+const getKeyString = (keys) => keys.includes(Key.All) ? "All" : keys.sort().join("+");
const handlers = {
down: {},
up: {}
};
const pressedKeys = /* @__PURE__ */ new Set();
const onKeydown = (event) => {
- pressedKeys.add(event.code);
+ const key = event.code;
+ pressedKeys.add(key);
const pressedArray = Array.from(pressedKeys);
const keyString = getKeyString(pressedArray);
if (handlers.down[keyString]) {
@@ -17,13 +18,16 @@ const onKeydown = (event) => {
}
eventHandler.handler(event);
if (eventHandler.once) {
- handlers.down[keyString] = handlers.down[keyString].filter((h) => h !== eventHandler);
+ handlers.down[keyString] = handlers.down[keyString].filter(
+ (h) => h !== eventHandler
+ );
}
});
}
};
const onKeyup = (event) => {
- pressedKeys.delete(event.code);
+ const key = event.code;
+ pressedKeys.delete(key);
const releasedArray = Array.from(pressedKeys);
const keyString = getKeyString(releasedArray);
if (handlers.up[keyString]) {
@@ -33,13 +37,16 @@ const onKeyup = (event) => {
}
eventHandler.handler(event);
if (eventHandler.once) {
- handlers.up[keyString] = handlers.up[keyString].filter((h) => h !== eventHandler);
+ handlers.up[keyString] = handlers.up[keyString].filter(
+ (h) => h !== eventHandler
+ );
}
});
}
};
const init = () => {
stop();
+ pressedKeys.clear();
window.addEventListener("keydown", onKeydown);
window.addEventListener("keyup", onKeyup);
};
@@ -47,6 +54,20 @@ const stop = () => {
window.removeEventListener("keydown", onKeydown);
window.removeEventListener("keyup", onKeyup);
};
+const unregisterAll = () => {
+ Object.keys(handlers.down).forEach((key) => {
+ handlers.down[key].forEach((handler) => {
+ console.log(`Unregistering ${key} ${handler.handler.toString()}`);
+ });
+ });
+ Object.keys(handlers.up).forEach((key) => {
+ handlers.up[key].forEach((handler) => {
+ console.log(`Unregistering ${key} ${handler.handler.toString()}`);
+ });
+ });
+ handlers.down = {};
+ handlers.up = {};
+};
const down = (keys, handler, config = {}) => {
if (keys.includes(Key.All)) {
keys = [Key.All];
@@ -59,6 +80,7 @@ const down = (keys, handler, config = {}) => {
handlers.down[key] = [];
}
const { once = false, prevent = false } = config;
+ console.log(key, handler.toString());
handlers.down[key].push({ handler, prevent, once });
};
const up = (keys, handler, config = {}) => {
@@ -84,6 +106,7 @@ const keyboard = defineNuxtPlugin((nuxtApp) => {
keyboard: {
init,
stop,
+ unregisterAll,
down: (keys, handler, config = {}) => down(keys, handler, config),
up: (keys, handler, config = {}) => up(keys, handler, config),
prevent: {