diff --git a/src/electron/App/CommunicationMessages.ts b/src/electron/App/CommunicationMessages.ts index c57e884..e16aa0a 100644 --- a/src/electron/App/CommunicationMessages.ts +++ b/src/electron/App/CommunicationMessages.ts @@ -1,39 +1,39 @@ export type IMessages = { - downloadLinkWritten: { - ok: string - }, - accountAndDataDeleted: { - ok: string - fail: string - }, - dataDeleted: { - ok: string - fail: string - }, - generic: { - ok: string, - fail: string - } + downloadLinkWritten: { + ok: string + } + accountAndDataDeleted: { + ok: string + fail: string + } + dataDeleted: { + ok: string + fail: string + } + generic: { + ok: string + fail: string + } } const en: IMessages = { - downloadLinkWritten: { - ok: `The link was written to the clipboard.\nPaste it in a browser and the database will download.\nRemember to keep it a secret!` - }, - accountAndDataDeleted: { - ok: "Account and your data were successfully deleted", - fail: "Failed to delete your account and/or data" - }, - dataDeleted: { - ok: "Failed to delete your data", - fail: "Data successfully deleted" - }, - generic: { - ok: "Operation successfully completed", - fail: "Operation failed" - } + downloadLinkWritten: { + ok: `The link was written to the clipboard.\nPaste it in a browser and the database will download.\nRemember to keep it a secret!` + }, + accountAndDataDeleted: { + ok: 'Account and your data were successfully deleted', + fail: 'Failed to delete your account and/or data' + }, + dataDeleted: { + ok: 'Failed to delete your data', + fail: 'Data successfully deleted' + }, + generic: { + ok: 'Operation successfully completed', + fail: 'Operation failed' + } } -export const messages = (lang: "en" | "tbd" = "en"): IMessages => { - return en -} \ No newline at end of file +export const messages = (lang: 'en' | 'tbd' = 'en'): IMessages => { + return en +} diff --git a/src/electron/App/EventHandler.ts b/src/electron/App/EventHandler.ts index 92d853e..8d3082c 100644 --- a/src/electron/App/EventHandler.ts +++ b/src/electron/App/EventHandler.ts @@ -327,7 +327,7 @@ async function registerUser(rawUser: { name: string; password: string }) { } /** - * Events send by the front-end, not Iohook specific + * from frontend, not Iohook specific */ const channelsFromRender: IReceiveChannel[] = [ { @@ -484,6 +484,33 @@ const channelsFromRender: IReceiveChannel[] = [ handler: async (event: any) => { actionsExported.askPassword() } + }, + { + name: 'to.backend.openImage', + handler: async (event: any, hash: string, width: number, height: number) => { + const item = await ItemRepo.get(hash) + if (!item || item.contentType !== 3) { + actionsExported.alertFrontend('cannot open a non image') + } + const win = new BrowserWindow({ + height, + width, + show: false, + autoHideMenuBar: true + }) + + const content = `data:text/html;charset=utf-8,image taken on ${item?.modified.toLocaleString()} ` + win.loadURL(content) + win.setAlwaysOnTop(true, 'floating') + win.setVisibleOnAllWorkspaces(true) + win.once('ready-to-show', () => { + win.show() + }) + win.focus() + win + } } ] diff --git a/src/electron/Data/ItemRepository.ts b/src/electron/Data/ItemRepository.ts index ec6ad62..22e3a96 100644 --- a/src/electron/Data/ItemRepository.ts +++ b/src/electron/Data/ItemRepository.ts @@ -38,7 +38,6 @@ const update = (item: IClipboardItem): boolean => { return false } - const remove = async (hash: string) => { items.delete(hash) await RequestService.clips.delete(hash) @@ -96,7 +95,7 @@ async function loadItemsBeforeDate(date: DateTime, limit: number, masterKey: str } let needsLoading = false if (!state.user) { - throw new Error("user not found") + throw new Error('user not found') } // console.log("received items: " + res.data.clips.length) for (const clip of res.data.clips) { @@ -136,18 +135,18 @@ export const ItemRepo = { loadItemsBeforeHash: async (hash: string, password: string, limit = 50) => { const item = items.get(hash) if (!item) { - throw new Error("tried to read before unexisting hash!") + throw new Error('tried to read before unexisting hash!') } return loadItemsBeforeDate(DateTime.fromJSDate(item.modified), limit, password) }, cleanUp: async (maxAgeInSeconds: number, maxNumberTotal: number): Promise => { let changed = false - changed = changed || await removeOldUnfavored(maxAgeInSeconds) - changed = changed || await limitMapSize(maxNumberTotal) + changed = changed || (await removeOldUnfavored(maxAgeInSeconds)) + changed = changed || (await limitMapSize(maxNumberTotal)) return changed }, syncWithRemote: async (password: string) => { - console.log("syncing") + console.log('syncing') const res = await RequestService.clips.getSince(oldestPull) if (!res.ok || !res.data) { actionsExported.logFrontend(messages().generic.fail + `.\nFetch of items since ${oldestPull.toISO()}.`) @@ -156,9 +155,9 @@ export const ItemRepo = { oldestPull = DateTime.now() let needsLoading = false if (!state.user) { - throw new Error("user not found") + throw new Error('user not found') } - console.log("received items after sync: " + res.data.clips.length) + console.log('received items after sync: ' + res.data.clips.length) for (const clip of res.data.clips) { needsLoading = true try { @@ -185,8 +184,7 @@ export const ItemRepo = { item[1].remoteStatus = RemoteItemStatus.pushedToRemote } else if (res.status == 409) { item[1].remoteStatus = RemoteItemStatus.needsUpdateOnRemote - } - else { + } else { console.log(await res.text()) } needsLoading = true @@ -204,7 +202,7 @@ export const ItemRepo = { } console.log('done syncing') if (needsLoading) { - console.log("needs loading after remote sync") + console.log('needs loading after remote sync') actionsExported.sendCurrentItems() } } diff --git a/src/electron/Data/RequestUtils.ts b/src/electron/Data/RequestUtils.ts index e4fde43..e3e70eb 100644 --- a/src/electron/Data/RequestUtils.ts +++ b/src/electron/Data/RequestUtils.ts @@ -5,16 +5,13 @@ export const ClipsEndpoints = { CreateUpdate: `${userPreferences.storeUrl.value}/v1/clips`, Delete: (hash: string) => `${userPreferences.storeUrl.value}/v1/clips/${hash}`, GetOne: (hash: string) => `${userPreferences.storeUrl.value}/v1/clips/${hash}`, - GetAllSince: (time: DateTime) => - `${userPreferences.storeUrl.value}/v1/clips/since/${time.toUTC().toISO()}`, + GetAllSince: (time: DateTime) => `${userPreferences.storeUrl.value}/v1/clips/since/${time.toUTC().toISO()}`, GetNBefore: (time: DateTime, limit: number) => `${userPreferences.storeUrl.value}/v1/clips/before/${time.toUTC().toISO()}/limit/${limit}`, GetInBetween: (start: DateTime, end: DateTime) => `${userPreferences.storeUrl.value}/v1/clips/between/${start.toUTC().toISO()}/${end.toUTC().toISO()}`, - DeletAllData: () => - `${userPreferences.storeUrl.value}/v1/deleteMyData`, - GetDatabaseFile: () => - `${userPreferences.storeUrl.value}/v1/database` + DeletAllData: () => `${userPreferences.storeUrl.value}/v1/deleteMyData`, + GetDatabaseFile: () => `${userPreferences.storeUrl.value}/v1/database` } export const UserEndpoints = { @@ -22,5 +19,5 @@ export const UserEndpoints = { Login: `${userPreferences.authUrl.value}/v1/login`, RefreshToken: `${userPreferences.authUrl.value}/v1/refresh`, DeleteProfile: `${userPreferences.authUrl.value}/v1/deleteAccount`, - Confirm2FA: `${userPreferences.authUrl.value}/v1/confirm2fa`, + Confirm2FA: `${userPreferences.authUrl.value}/v1/confirm2fa` } diff --git a/src/electron/Data/Requests.ts b/src/electron/Data/Requests.ts index 0644482..25e8e67 100644 --- a/src/electron/Data/Requests.ts +++ b/src/electron/Data/Requests.ts @@ -1,9 +1,9 @@ -import { DateTime } from "luxon" +import { DateTime } from 'luxon' import fetch from 'node-fetch' -import { actionsExported } from "../App/EventHandler" -import { IClipboardItemEncrypted } from "../DataModels/DataTypes" -import { BulkRes, CommonRes, LoginRes, RefreshRes, RegisterRes } from "../DataModels/RequestTypes" -import { ClipsEndpoints, UserEndpoints } from "./RequestUtils" +import { actionsExported } from '../App/EventHandler' +import { IClipboardItemEncrypted } from '../DataModels/DataTypes' +import { BulkRes, CommonRes, LoginRes, RefreshRes, RegisterRes } from '../DataModels/RequestTypes' +import { ClipsEndpoints, UserEndpoints } from './RequestUtils' export const userTokens: Tokens = { access_expires: DateTime.now() @@ -15,12 +15,12 @@ type Tokens = { access_expires: DateTime } -function request(url: string, method: string = "GET", body?: object, headers?: Record) { +function request(url: string, method: string = 'GET', body?: object, headers?: Record) { if (!headers) { headers = {} } if (body) { - headers["content-type"] = "application/json" + headers['content-type'] = 'application/json' } const opts = { @@ -33,20 +33,25 @@ function request(url: string, method: string = "GET", body?: object, headers?: R } type ResWrapped = { - ok: boolean, - data?: T, + ok: boolean + data?: T err?: string code: number } -async function requestWithResponseBody(url: string, method: string = "GET", body?: object, headers?: Record): Promise> { +async function requestWithResponseBody( + url: string, + method: string = 'GET', + body?: object, + headers?: Record +): Promise> { const res = await request(url, method, body, headers) const result: ResWrapped = { ok: res.ok, code: res.status } if (res.ok) { - result.data = await res.json() as T + result.data = (await res.json()) as T } else { result.err = await res.text() } @@ -56,7 +61,7 @@ async function requestWithResponseBody(url: string, method: string = "GET", b async function getAccessToken(): Promise { if (DateTime.now().plus({ minute: 1 }) > userTokens.access_expires) { - console.log("access token needs a refresh!") + console.log('access token needs a refresh!') const refreshRes = await RequestService.account.refresh() if (refreshRes.ok && refreshRes.data) { userTokens.access_expires = DateTime.now().plus({ minutes: 55 }) @@ -66,25 +71,30 @@ async function getAccessToken(): Promise { } } if (!userTokens.access) { - actionsExported.logFrontend("Tried to call using an empty token!") - throw new Error("token not set") + actionsExported.logFrontend('Tried to call using an empty token!') + throw new Error('token not set') } return userTokens.access } -async function requestToken(url: string, method: string = "GET", body?: object) { - return await request(url, method, body, { 'authorization': `Bearer ${await getAccessToken()}` }) +async function requestToken(url: string, method: string = 'GET', body?: object) { + return await request(url, method, body, { authorization: `Bearer ${await getAccessToken()}` }) } -async function requestTokenBody(url: string, method: string = "GET", body?: object) { - return requestWithResponseBody(url, method, body, { 'authorization': `Bearer ${await getAccessToken()}` }) +async function requestTokenBody(url: string, method: string = 'GET', body?: object) { + return requestWithResponseBody(url, method, body, { authorization: `Bearer ${await getAccessToken()}` }) } export const RequestService = { account: { - register: (username: string, remotePass: string) => requestWithResponseBody(UserEndpoints.Register, "POST", { username, password: remotePass }), - login: (username: string, remotePass: string, code2fa: string) => requestWithResponseBody(UserEndpoints.Login, "POST", { username, password: remotePass, code: code2fa }), - refresh: () => requestWithResponseBody(UserEndpoints.RefreshToken, "POST", undefined, { "authorization": `Bearer ${userTokens.refresh}` }), + register: (username: string, remotePass: string) => + requestWithResponseBody(UserEndpoints.Register, 'POST', { username, password: remotePass }), + login: (username: string, remotePass: string, code2fa: string) => + requestWithResponseBody(UserEndpoints.Login, 'POST', { username, password: remotePass, code: code2fa }), + refresh: () => + requestWithResponseBody(UserEndpoints.RefreshToken, 'POST', undefined, { + authorization: `Bearer ${userTokens.refresh}` + }), logout() { userTokens.refresh = undefined userTokens.access = undefined @@ -95,18 +105,24 @@ export const RequestService = { const url = ClipsEndpoints.GetDatabaseFile() + `?token=${await getAccessToken()}` return url }, - confirm2fa: (code: string, token: string) => requestWithResponseBody(UserEndpoints.Confirm2FA, "POST", { - code - }, { "authorization": `Bearer ${token}` }) + confirm2fa: (code: string, token: string) => + requestWithResponseBody( + UserEndpoints.Confirm2FA, + 'POST', + { + code + }, + { authorization: `Bearer ${token}` } + ) }, clips: { - add: (clip: IClipboardItemEncrypted) => requestToken(ClipsEndpoints.CreateUpdate, "POST", clip), - upsert: (clip: IClipboardItemEncrypted) => requestToken(ClipsEndpoints.CreateUpdate, "PUT", clip), - update: (clip: { isFavorite: boolean, hash: string }) => requestToken(ClipsEndpoints.CreateUpdate, "PATCH", clip), - delete: (hash: string) => requestToken(ClipsEndpoints.Delete(hash), "DELETE"), - getSince: (time: DateTime) => requestTokenBody(ClipsEndpoints.GetAllSince(time), "GET"), - getBetween: (start: DateTime, end: DateTime) => requestTokenBody(ClipsEndpoints.GetInBetween(start, end), "GET"), - getNBefore: (time: DateTime, limit: number) => requestTokenBody(ClipsEndpoints.GetNBefore(time, limit), "GET"), - deleteAll: () => requestTokenBody(ClipsEndpoints.DeletAllData(), "DELETE"), + add: (clip: IClipboardItemEncrypted) => requestToken(ClipsEndpoints.CreateUpdate, 'POST', clip), + upsert: (clip: IClipboardItemEncrypted) => requestToken(ClipsEndpoints.CreateUpdate, 'PUT', clip), + update: (clip: { isFavorite: boolean; hash: string }) => requestToken(ClipsEndpoints.CreateUpdate, 'PATCH', clip), + delete: (hash: string) => requestToken(ClipsEndpoints.Delete(hash), 'DELETE'), + getSince: (time: DateTime) => requestTokenBody(ClipsEndpoints.GetAllSince(time), 'GET'), + getBetween: (start: DateTime, end: DateTime) => requestTokenBody(ClipsEndpoints.GetInBetween(start, end), 'GET'), + getNBefore: (time: DateTime, limit: number) => requestTokenBody(ClipsEndpoints.GetNBefore(time, limit), 'GET'), + deleteAll: () => requestTokenBody(ClipsEndpoints.DeletAllData(), 'DELETE') } -} \ No newline at end of file +} diff --git a/src/electron/DataModels/DataTypes.ts b/src/electron/DataModels/DataTypes.ts index 7bdf602..bd8b83c 100644 --- a/src/electron/DataModels/DataTypes.ts +++ b/src/electron/DataModels/DataTypes.ts @@ -1,6 +1,5 @@ import stringify from 'json-stable-stringify' - // export interface IItemsDb { // Add(item: IClipboardItemEncrypted): Promise // GetRange(start: number, end: number): Promise @@ -68,7 +67,7 @@ export enum RemoteItemStatus { } export interface IClipboardItem extends ItemBase { - content: string; + content: string created: Date modified: Date remoteStatus: RemoteItemStatus diff --git a/src/electron/DataModels/RequestTypes.ts b/src/electron/DataModels/RequestTypes.ts index c90aee1..4838609 100644 --- a/src/electron/DataModels/RequestTypes.ts +++ b/src/electron/DataModels/RequestTypes.ts @@ -1,4 +1,4 @@ -import { IClipboardItemEncrypted } from "./DataTypes"; +import { IClipboardItemEncrypted } from './DataTypes' export interface CommonRes { message: string @@ -13,21 +13,20 @@ export interface LoginResTotp { } export interface TotpRes { - qr : string - secret : string - token : string + qr: string + secret: string + token: string } export interface RefreshRes { - access_token: string; - type: string; + access_token: string + type: string } export interface LoginRes extends RefreshRes { - refresh_token: string; + refresh_token: string } - export interface BulkRes { clips: IClipboardItemEncrypted[] -} \ No newline at end of file +} diff --git a/src/electron/index.ts b/src/electron/index.ts index 7846966..7b942be 100644 --- a/src/electron/index.ts +++ b/src/electron/index.ts @@ -6,7 +6,6 @@ import CustomWindow from './App/CustomWindow' import { channelsToRender, ioHookHandler } from './App/EventHandler' import { userPreferences } from './App/UserPreferences' - let mainWindow: CustomWindow let appIcon: Tray @@ -70,9 +69,9 @@ app.on('ready', async () => { appIcon.setToolTip(AppSettings.name) if (AppSettings.openDevTools) { - console.log("open dev tools!") + console.log('open dev tools!') setTimeout(() => { - mainWindow.window.webContents.openDevTools({ mode: "detach" }) + mainWindow.window.webContents.openDevTools({ mode: 'detach' }) }, 1000) } if (AppSettings.isMac) { @@ -117,16 +116,15 @@ app.on('window-all-closed', () => { app.quit() }) - if (AppSettings.isLinux) { - app.commandLine.appendSwitch('disable-gpu-sandbox'); + app.commandLine.appendSwitch('disable-gpu-sandbox') } if (AppSettings.enableDevTools && AppSettings.isLinux) { const port = '8315' console.log(`starting debugging on port: ${port}. Open http://localhost:${port}`) - app.commandLine.appendSwitch('remote-debugging-port', port); - app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1'); + app.commandLine.appendSwitch('remote-debugging-port', port) + app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1') } function stopProcessReuse() { diff --git a/src/frontend/Components/Button.svelte b/src/frontend/Components/Button.svelte index 02e9a7a..ff3cf02 100644 --- a/src/frontend/Components/Button.svelte +++ b/src/frontend/Components/Button.svelte @@ -15,7 +15,7 @@ {#if visible}

{label} diff --git a/src/frontend/Components/Clips.svelte b/src/frontend/Components/Clips.svelte index 10e0a9d..b798038 100644 --- a/src/frontend/Components/Clips.svelte +++ b/src/frontend/Components/Clips.svelte @@ -68,9 +68,20 @@ currentPage.set(IPages.login) } }) + function saveBlob(blob: any, fileName: string) { + var a = document.createElement('a') + document.body.appendChild(a) + a.style = 'display: none' + + var url = window.URL.createObjectURL(blob) + a.href = url + a.download = fileName + a.click() + window.URL.revokeObjectURL(url) + } -

+
{#if $clipListFiltered} {#each $clipListFiltered as [key, item]} {#if visibleHashes.includes(key) || visibleHashes.includes(getPreviousHash(key, -1)) || visibleHashes.includes(getPreviousHash(key, 1)) || visibleHashes.includes(getPreviousHash(key, -2)) || visibleHashes.includes(getPreviousHash(key, 2)) || visibleHashes.includes(getPreviousHash(key, -3)) || visibleHashes.includes(getPreviousHash(key, 3))} @@ -79,9 +90,9 @@ on:enterViewport={() => handleEnter(key)} on:exitViewport={() => handleExit(key)} title={getTitle(item)} - class="clipboard-item border-slate-800 {$selectedClipId === item.hash - ? 'bg-gray-300 even:bg-gray-300 hover:bg-gray-100 dark:bg-slate-700 even:dark:bg-slate-700 dark:hover:bg-slate-500' - : 'bg-gray-100 even:bg-white hover:bg-gray-300 dark:bg-rock even:dark:bg-slate-900 dark:hover:bg-slate-700'} dark:text-gray-100 dark:even:border-y" + class="clipboard-item border-zinc-800 {$selectedClipId === item.hash + ? 'bg-neutral-300 even:bg-neutral-300 hover:bg-neutral-100 dark:bg-zinc-700 even:dark:bg-zinc-700 dark:hover:bg-zinc-500' + : 'bg-neutral-100 even:bg-white hover:bg-neutral-300 dark:bg-neutral-900 even:dark:bg-zinc-900 dark:hover:bg-zinc-700'} dark:text-neutral-100 dark:even:border-y" id={item.hash} on:click|preventDefault={() => handleClick(item)} > @@ -93,11 +104,43 @@ {/if} {/if} -
+
{#if isTextContent(item)}

{item.content}

{:else if isImageContent(item)} Base64png +
+ + +
{/if}
@@ -108,7 +151,7 @@ {/if} {/each} {:else} -

No items!

+

No items!

{/if}
@@ -123,6 +166,6 @@ } ::selection { - @apply bg-gray-500 text-white; + @apply bg-neutral-500 text-white; } diff --git a/src/frontend/Components/Debug.svelte b/src/frontend/Components/Debug.svelte index aa3eb17..9933435 100644 --- a/src/frontend/Components/Debug.svelte +++ b/src/frontend/Components/Debug.svelte @@ -27,16 +27,16 @@

Pressed keys:

{#each keys as key} -

+

{key.length > 0 ? key : '[nothing pressed]'}

{/each} @@ -44,7 +44,7 @@ even:dark:bg-slate-900"

Logs:

{#each $backendLogs as log} -

+

{log}

{/each} diff --git a/src/frontend/Components/Login.svelte b/src/frontend/Components/Login.svelte index c596263..22a019d 100644 --- a/src/frontend/Components/Login.svelte +++ b/src/frontend/Components/Login.svelte @@ -10,8 +10,8 @@ passwordButtonText, showPassword } from '../stores' - import Icons from './icons/Icons.svelte' import { IPages } from '../types' + import Icons from './icons/Icons.svelte' function togglePasswordInput() { $passwordButtonText === 'show' ? ($passwordButtonText = 'hide') : ($passwordButtonText = 'show') @@ -75,7 +75,11 @@ } const onKeyEnter = async (e: KeyboardEvent) => { if (e.key == 'Enter') { - sendRequest() + if ($isUserRemembered) { + unlock() + } else { + sendRequest() + } } } const onOkay = (e: Event) => { @@ -116,7 +120,7 @@
{#if $isUserRemembered} -
+

Your clipboard manager is locked

@@ -140,7 +144,7 @@
@@ -149,7 +153,7 @@ bind:value={userPassword} on:input={resetPasswordCorrect} on:keypress={onKeyEnter} - class="border-1 w-full appearance-none border-gray-300 bg-gray-100 px-3 py-3 pr-16 font-mono leading-tight text-gray-700 focus:border-gray-500 focus:bg-gray-200 focus:outline-none dark:bg-slate-800 dark:text-gray-200 dark:focus:bg-gray-800" + class="border-1 w-full appearance-none border-zinc-300 bg-zinc-100 px-3 py-3 pr-16 font-mono leading-tight text-zinc-700 focus:border-zinc-500 focus:bg-zinc-200 focus:outline-none dark:bg-zinc-800 dark:text-zinc-200 dark:focus:bg-zinc-800" type="text" placeholder="password" autocomplete="off" @@ -159,7 +163,7 @@ bind:value={userPassword} on:input={resetPasswordCorrect} on:keypress={onKeyEnter} - class="border-1 dark:focus:bg-gray-800focus:outline-none w-full appearance-none border-gray-300 bg-gray-100 px-3 py-3 pr-16 font-mono leading-tight text-gray-700 focus:border-gray-500 focus:bg-gray-200 dark:bg-slate-800 dark:text-gray-200 dark:focus:bg-slate-700" + class="border-1 dark:focus:bg-zinc-800focus:outline-none w-full appearance-none border-zinc-300 bg-zinc-100 px-3 py-3 pr-16 font-mono leading-tight text-zinc-700 focus:border-zinc-500 focus:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-200 dark:focus:bg-neutral-700" type="password" placeholder="password" autocomplete="off" @@ -167,19 +171,19 @@ {/if}

or

{:else}
-
+

Login or Register

@@ -188,7 +192,7 @@ bind:this={usernameField} bind:value={username} on:input={resetPasswordCorrect} - class="border-1 w-full appearance-none border-gray-300 bg-gray-100 px-3 py-3 pr-16 font-mono leading-tight text-gray-700 focus:border-gray-500 focus:bg-gray-200 focus:outline-none dark:bg-slate-800 dark:text-gray-200 dark:focus:bg-gray-800" + class="border-1 w-full appearance-none border-zinc-300 bg-zinc-100 px-3 py-3 pr-16 font-mono leading-tight text-zinc-700 focus:border-zinc-500 focus:bg-zinc-200 focus:outline-none dark:bg-zinc-800 dark:text-zinc-200 dark:focus:bg-zinc-800" type="text" autocomplete="off" placeholder="username" @@ -199,7 +203,7 @@
@@ -208,7 +212,7 @@ bind:value={userPassword} on:input={resetPasswordCorrect} on:keypress={onKeyEnter} - class="border-1 w-full appearance-none border-gray-300 bg-gray-100 px-3 py-3 pr-16 font-mono leading-tight text-gray-700 focus:border-gray-500 focus:bg-gray-200 focus:outline-none dark:bg-slate-800 dark:text-gray-200 dark:focus:bg-gray-800" + class="border-1 w-full appearance-none border-zinc-300 bg-zinc-100 px-3 py-3 pr-16 font-mono leading-tight text-zinc-700 focus:border-zinc-500 focus:bg-zinc-200 focus:outline-none dark:bg-zinc-800 dark:text-zinc-200 dark:focus:bg-zinc-800" type="text" placeholder="password" autocomplete="off" @@ -218,7 +222,7 @@ bind:value={userPassword} on:input={resetPasswordCorrect} on:keypress={onKeyEnter} - class="border-1 dark:focus:bg-gray-800focus:outline-none w-full appearance-none border-gray-300 bg-gray-100 px-3 py-3 pr-16 font-mono leading-tight text-gray-700 focus:border-gray-500 focus:bg-gray-200 dark:bg-slate-800 dark:text-gray-200 dark:focus:bg-slate-700" + class="border-1 dark:focus:bg-zinc-800focus:outline-none w-full appearance-none border-zinc-300 bg-zinc-100 px-3 py-3 pr-16 font-mono leading-tight text-zinc-700 focus:border-zinc-500 focus:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-200 dark:focus:bg-neutral-700" type="password" placeholder="password" autocomplete="off" @@ -231,7 +235,7 @@ bind:value={userPasswordConfirm} on:input={resetPasswordCorrect} on:keypress={onKeyEnter} - class="border-1 w-full appearance-none border-gray-300 bg-gray-100 px-3 py-3 pr-16 font-mono leading-tight text-gray-700 focus:border-gray-500 focus:bg-gray-200 focus:outline-none dark:bg-slate-800 dark:text-gray-200 dark:focus:bg-gray-800" + class="border-1 w-full appearance-none border-zinc-300 bg-zinc-100 px-3 py-3 pr-16 font-mono leading-tight text-zinc-700 focus:border-zinc-500 focus:bg-zinc-200 focus:outline-none dark:bg-zinc-800 dark:text-zinc-200 dark:focus:bg-zinc-800" type="text" placeholder="confirm password" autocomplete="off" @@ -241,7 +245,7 @@ bind:value={userPasswordConfirm} on:input={resetPasswordCorrect} on:keypress={onKeyEnter} - class="border-1 dark:focus:bg-gray-800focus:outline-none w-full appearance-none border-gray-300 bg-gray-100 px-3 py-3 pr-16 font-mono leading-tight text-gray-700 focus:border-gray-500 focus:bg-gray-200 dark:bg-slate-800 dark:text-gray-200 dark:focus:bg-slate-700" + class="border-1 dark:focus:bg-zinc-800focus:outline-none w-full appearance-none border-zinc-300 bg-zinc-100 px-3 py-3 pr-16 font-mono leading-tight text-zinc-700 focus:border-zinc-500 focus:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-200 dark:focus:bg-neutral-700" type="password" placeholder="confirm password" autocomplete="off" @@ -252,7 +256,7 @@
-
+

{@html $loginPageMessage}

diff --git a/src/frontend/Components/MenuItem.svelte b/src/frontend/Components/MenuItem.svelte index 737e35f..e8d93ea 100644 --- a/src/frontend/Components/MenuItem.svelte +++ b/src/frontend/Components/MenuItem.svelte @@ -5,11 +5,11 @@
diff --git a/src/frontend/Components/PageHandler.svelte b/src/frontend/Components/PageHandler.svelte index 26be64b..66ce2c5 100644 --- a/src/frontend/Components/PageHandler.svelte +++ b/src/frontend/Components/PageHandler.svelte @@ -35,7 +35,7 @@
-
+
@@ -54,9 +54,9 @@ } .page::-webkit-scrollbar-track { - @apply w-2 border-l border-none border-gray-600 bg-gray-50 dark:bg-slate-600; + @apply w-2 border-l border-none border-neutral-600 bg-neutral-50 dark:bg-zinc-600; } .page::-webkit-scrollbar-thumb { - @apply w-2 bg-gray-300 dark:bg-gray-800; + @apply w-2 bg-neutral-300 dark:bg-neutral-800; } diff --git a/src/frontend/Components/Search.svelte b/src/frontend/Components/Search.svelte index 11cdfc3..11b2fce 100644 --- a/src/frontend/Components/Search.svelte +++ b/src/frontend/Components/Search.svelte @@ -30,7 +30,7 @@ { currentSearchedText.set($currentSearchedText) diff --git a/src/frontend/Components/SearchBar.svelte b/src/frontend/Components/SearchBar.svelte index 00c5b46..3545e8a 100644 --- a/src/frontend/Components/SearchBar.svelte +++ b/src/frontend/Components/SearchBar.svelte @@ -31,11 +31,11 @@ {#if $currentPage == IPages.items}
{#each data as key} -

{key}

+

+ {key} +

{data.indexOf(key) != data.length - 1 ? '+' : ''} {:else} -

nothing pressed

+

+ nothing pressed +

{/each}
diff --git a/src/frontend/Components/ShortcutsHandler.svelte b/src/frontend/Components/ShortcutsHandler.svelte index 2863b03..90eb5e9 100644 --- a/src/frontend/Components/ShortcutsHandler.svelte +++ b/src/frontend/Components/ShortcutsHandler.svelte @@ -3,7 +3,15 @@ import { delay } from '../KeyboardEventUtil' import { sendShortcuts } from '../backendActions' import { events, eventsToBackend } from '../events' - import { currentPage, currentSearchedText, isAppHidden, isFocused, pressedKeysSizeLimit, shortcutsJson, userPreferences } from '../stores' + import { + currentPage, + currentSearchedText, + isAppHidden, + isFocused, + pressedKeysSizeLimit, + shortcutsJson, + userPreferences + } from '../stores' import { IPages, type IShortCut } from '../types' import { clipListFiltered, currentScrollIndex, pressedKeys, selectedClipId } from './../stores' import Button from './Button.svelte' @@ -370,10 +378,10 @@ > {#each entries(shortcuts) as shortcut}
diff --git a/src/frontend/Components/Switch.svelte b/src/frontend/Components/Switch.svelte index 7c7ee2c..f7df7ea 100644 --- a/src/frontend/Components/Switch.svelte +++ b/src/frontend/Components/Switch.svelte @@ -10,8 +10,7 @@ export let value: any = undefined export let title: string | undefined = undefined - onMount(() => { - }) + onMount(() => {}) function handleClick(event) { if (selectOptions) return @@ -35,7 +34,7 @@
{#if type === 'select'} {label} - {#each selectOptions as option} {#if option === value} @@ -51,13 +50,13 @@ {label} {:else if type === 'string'} {label} - + {/if}
@@ -81,7 +80,7 @@ position: relative; border: none; border-radius: 1.5em; - @apply m-0 h-5 min-h-[1.25rem] w-9 min-w-[2.25rem] shadow duration-500 dark:bg-gray-800; + @apply m-0 h-5 min-h-[1.25rem] w-9 min-w-[2.25rem] shadow duration-500 dark:bg-neutral-800; } .slider button::before { @@ -89,15 +88,15 @@ position: absolute; right: 1.5em; transition: transform 0.3s; - @apply top-[0.125rem] h-4 w-4 bg-gray-300 dark:bg-slate-900; + @apply top-[0.125rem] h-4 w-4 bg-neutral-300 dark:bg-zinc-900; } .slider button[aria-checked='true'] { - @apply bg-gray-300 dark:bg-slate-500; + @apply bg-neutral-300 dark:bg-zinc-500; } .slider button[aria-checked='true']::before { - @apply translate-x-4 bg-gray-50 transition-transform duration-300 dark:bg-gray-800; + @apply translate-x-4 bg-neutral-50 transition-transform duration-300 dark:bg-neutral-800; } .slider button::before { diff --git a/src/frontend/Components/TitleBar.svelte b/src/frontend/Components/TitleBar.svelte index 4c7d832..887c5b8 100644 --- a/src/frontend/Components/TitleBar.svelte +++ b/src/frontend/Components/TitleBar.svelte @@ -20,7 +20,7 @@
diff --git a/src/frontend/Components/TotpConfirm.svelte b/src/frontend/Components/TotpConfirm.svelte index b59db13..b165061 100644 --- a/src/frontend/Components/TotpConfirm.svelte +++ b/src/frontend/Components/TotpConfirm.svelte @@ -1,7 +1,7 @@
- \ No newline at end of file + + diff --git a/src/frontend/Components/icons/paths/heart.svelte b/src/frontend/Components/icons/paths/heart.svelte index 248b860..d16efdd 100644 --- a/src/frontend/Components/icons/paths/heart.svelte +++ b/src/frontend/Components/icons/paths/heart.svelte @@ -7,4 +7,4 @@ d="M39.728 23.9283L42.5563 21.1C45.1818 18.4745 48.7428 16.9995 52.4558 16.9995C56.1688 16.9995 59.7298 18.4745 62.3553 21.1C64.9808 23.7255 66.4558 27.2865 66.4558 30.9995C66.4558 34.7125 64.9808 38.2735 62.3553 40.899L41.1421 62.1122C40.7516 62.5027 40.2398 62.698 39.728 62.698" stroke-linecap="round" stroke-linejoin="round" -/> \ No newline at end of file +/> diff --git a/src/frontend/Components/icons/paths/trash-bin.svelte b/src/frontend/Components/icons/paths/trash-bin.svelte index ce0b4bf..77c21f6 100644 --- a/src/frontend/Components/icons/paths/trash-bin.svelte +++ b/src/frontend/Components/icons/paths/trash-bin.svelte @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/src/frontend/KeyboardEventUtil.ts b/src/frontend/KeyboardEventUtil.ts index efe054d..f38551d 100644 --- a/src/frontend/KeyboardEventUtil.ts +++ b/src/frontend/KeyboardEventUtil.ts @@ -296,6 +296,9 @@ export const getKeyName = (keycode: number, rawcode: number, layout: string, pla } } if (platform === 'mac') { + if (!result) { + return '' + } return result.replace(/Win/g, 'Command').replace(/Alt/g, 'Option') } return result diff --git a/src/frontend/backendActions.ts b/src/frontend/backendActions.ts index 61095eb..8d15fe0 100644 --- a/src/frontend/backendActions.ts +++ b/src/frontend/backendActions.ts @@ -1,4 +1,4 @@ -import { events, eventsToBackend } from "./events" +import { events, eventsToBackend } from './events' export function sendShortcuts(serialized: string) { events.notify(eventsToBackend.setShortcuts, serialized) diff --git a/src/frontend/events.ts b/src/frontend/events.ts index b2bfc6e..0d774e5 100644 --- a/src/frontend/events.ts +++ b/src/frontend/events.ts @@ -27,5 +27,6 @@ export const eventsToBackend = { windowUnhide: 'to.backend.window.unhide', setShortcuts: `to.backend.set.shortcuts`, confirm2fa: `to.backend.confirm.2fa`, - frontendEventsReady: `to.backend.frontendHandler.isReady` + frontendEventsReady: `to.backend.frontendHandler.isReady`, + openImage: `to.backend.openImage` } as const diff --git a/src/frontend/types.ts b/src/frontend/types.ts index b2b3539..87d85ea 100644 --- a/src/frontend/types.ts +++ b/src/frontend/types.ts @@ -76,10 +76,10 @@ export enum RemoteItemStatus { } export interface IClipboardItem extends ItemBase { - content: string; + content: string created: Date modified: Date - remoteStatus: RemoteItemStatus, + remoteStatus: RemoteItemStatus } export interface IClipboardItemFrontend extends IClipboardItem { @@ -134,7 +134,7 @@ export interface IHookKeyboardEvent { } export interface TotpRes { - qr : string - secret : string - token : string -} \ No newline at end of file + qr: string + secret: string + token: string +} diff --git a/src/frontend/util.ts b/src/frontend/util.ts index bd7c0ee..af8724d 100644 --- a/src/frontend/util.ts +++ b/src/frontend/util.ts @@ -1,15 +1,15 @@ -import { DateTime } from "luxon" +import { DateTime } from 'luxon' export const timestampToRelativeTime = (timestamp: number) => DateTime.fromMillis(timestamp) .minus({ minute: 1 }) - .toRelative({ style: "narrow", round: true }) - .replace(" ago", "") - .replace(" min", "m") - .replace(" day", "d") - .replace(" year", "y") - .replace(" week", "w") - .replace(" sec", "-") - .replace("s", "") - .replace("-", "s") - .replace(" hr", "h") \ No newline at end of file + .toRelative({ style: 'narrow', round: true }) + .replace(' ago', '') + .replace(' min', 'm') + .replace(' day', 'd') + .replace(' year', 'y') + .replace(' week', 'w') + .replace(' sec', '-') + .replace('s', '') + .replace('-', 's') + .replace(' hr', 'h') diff --git a/src/frontend/www/tailwind.pcss b/src/frontend/www/tailwind.pcss index 338a72c..a74e397 100644 --- a/src/frontend/www/tailwind.pcss +++ b/src/frontend/www/tailwind.pcss @@ -16,7 +16,7 @@ } html, body { - @apply flex relative w-full h-full m-0 box-border text-gray-900 dark:bg-rock; + @apply flex relative w-full h-full m-0 box-border text-neutral-900 dark:bg-stone-900; } body { @apply overflow-y-hidden; diff --git a/tailwind.config.js b/tailwind.config.js index f6b6306..125ecee 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -14,7 +14,9 @@ module.exports = { yellow: colors.yellow, slate: colors.slate, green: colors.green, - stone: colors.stone + stone: colors.stone, + zinc: colors.zinc, + neutral: colors.neutral }, extend: {} },