diff --git a/dev.js b/dev.js
index 59a0a5a..6fc68f7 100644
--- a/dev.js
+++ b/dev.js
@@ -1,21 +1,21 @@
-import updates from "pear-updates";
-import { spawn } from "bare-subprocess";
-import { isWindows } from ".";
+import updates from 'pear-updates'
+import { spawn } from 'bare-subprocess'
+import { isWindows } from '.'
isWindows
- ? spawn("npm.cmd", ["run", "build"], { stdio: "inherit" })
- : spawn("npm", ["run", "build"], { stdio: "inherit" });
+ ? spawn('npm.cmd', ['run', 'build'], { stdio: 'inherit' })
+ : spawn('npm', ['run', 'build'], { stdio: 'inherit' })
-const REGULATE = 500;
-let throttle = Date.now() + REGULATE;
+const REGULATE = 500
+let throttle = Date.now() + REGULATE
updates({ app: true, version: { key: null } }, (update) => {
- if (Date.now() < throttle) return;
- throttle = Infinity;
- console.log("Update", update);
+ if (Date.now() < throttle) return
+ throttle = Infinity
+ console.log('Update', update)
const build = isWindows
- ? spawn("npm.cmd", ["run", "build"], { stdio: "inherit" })
- : spawn("npm", ["run", "build"], { stdio: "inherit" });
- build.on("close", () => {
- throttle = Date.now() + REGULATE;
- });
-});
+ ? spawn('npm.cmd', ['run', 'build'], { stdio: 'inherit' })
+ : spawn('npm', ['run', 'build'], { stdio: 'inherit' })
+ build.on('close', () => {
+ throttle = Date.now() + REGULATE
+ })
+})
diff --git a/index.js b/index.js
index 68ad6a8..16aa26b 100644
--- a/index.js
+++ b/index.js
@@ -1,17 +1,17 @@
/* global Pear */
-import Runtime from "pear-electron";
-import Bridge from "pear-bridge";
-import process from "bare-process";
+import Runtime from 'pear-electron'
+import Bridge from 'pear-bridge'
+import process from 'bare-process'
-const onDisk = Pear.app.key === null;
-if (onDisk) await import("./dev.js");
+const onDisk = Pear.app.key === null
+if (onDisk) await import('./dev.js')
-const bridge = new Bridge();
-await bridge.ready();
-const runtime = new Runtime();
+const bridge = new Bridge()
+await bridge.ready()
+const runtime = new Runtime()
-const pipe = await runtime.start({ bridge });
+const pipe = await runtime.start({ bridge })
-pipe.on("end", () => Pear.exit());
+pipe.on('end', () => Pear.exit())
-export const isWindows = process.platform === "win32";
+export const isWindows = process.platform === 'win32'
diff --git a/package-lock.json b/package-lock.json
index 300ff9f..0df3530 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -640,6 +640,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -1298,6 +1299,7 @@
"resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz",
"integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"bare-path": "^3.0.0"
}
@@ -2131,6 +2133,7 @@
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -2328,6 +2331,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@@ -2382,6 +2386,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz",
"integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"builtins": "^5.0.1",
"eslint-plugin-es": "^4.1.0",
@@ -2419,6 +2424,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz",
"integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==",
"license": "ISC",
+ "peer": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -2434,6 +2440,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
"integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"array-includes": "^3.1.8",
"array.prototype.findlast": "^1.2.5",
@@ -4966,6 +4973,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
diff --git a/src/App.css b/src/App.css
index 84b2a7a..5d656af 100644
--- a/src/App.css
+++ b/src/App.css
@@ -764,7 +764,7 @@ textarea:focus {
display: flex;
flex-direction: column;
gap: 0.5rem;
- padding: 0.5rem 0.25rem 0.5rem 0.5rem;
+ padding: 0.5rem 0.75rem 0.5rem 0.5rem;
overflow: auto;
flex: 1;
}
@@ -964,7 +964,7 @@ textarea:focus {
background: var(--bg-secondary);
box-shadow: 2px 2px 0 var(--border);
min-width: 140px;
- z-index: 1001;
+ z-index: 999;
display: flex;
flex-direction: column;
padding: 0.25rem;
diff --git a/src/App.jsx b/src/App.jsx
index b69a006..71f9873 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,40 +1,40 @@
/* global alert */
-import React from "react";
-import { createRoot } from "react-dom/client";
-import { SideBar } from "@/src/components/layout/SideBar.jsx";
-import ToggleSwitch from "@/src/components/ui/ToggleSwitch.jsx";
-import { DecryptPopUp } from "@/src/components/popups/DecryptPopUp.jsx";
-import { Overlay } from "@/src/components/layout/Overlay.jsx";
-import Alert from "@/src/components/popups/Alert.jsx";
-import { PasswordManager } from "@/src/features/passwords/PasswordManager.jsx";
-import { NoteManager } from "@/src/features/notes/NoteManager.jsx";
-import { AddPasswordForm } from "@/src/features/passwords/AddPasswordForm";
-import { AddNoteForm } from "@/src/features/notes/AddNoteForm";
-import { GeneratePasswordForm } from "@/src/features/passwords/GeneratePasswordForm.jsx";
-import { SetupVault } from "@/src/features/setup/SetupVault.jsx";
-import { useOptionStore } from "@/src/store/optionStore.js";
-import { useGlobalStore } from "@/src/store/globalStore.js";
-import { useShallow } from "zustand/react/shallow";
-import { vaultPass } from "@/src/lib/vaultPass.js";
-import { FaCopy } from "react-icons/fa";
-import { BiExit, BiExport } from "react-icons/bi";
-import { IoFlash } from "react-icons/io5";
-import { FiKey, FiPlus, FiRefreshCcw, FiShare, FiUpload } from "react-icons/fi";
-import "@/src/App.css";
-import { Loader } from "./components/ui/Loader";
-import { encryptString, decryptString } from "./lib/crpyto";
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { SideBar } from '@/src/components/layout/SideBar.jsx'
+import ToggleSwitch from '@/src/components/ui/ToggleSwitch.jsx'
+import { DecryptPopUp } from '@/src/components/popups/DecryptPopUp.jsx'
+import { Overlay } from '@/src/components/layout/Overlay.jsx'
+import Alert from '@/src/components/popups/Alert.jsx'
+import { PasswordManager } from '@/src/features/passwords/PasswordManager.jsx'
+import { NoteManager } from '@/src/features/notes/NoteManager.jsx'
+import { AddPasswordForm } from '@/src/features/passwords/AddPasswordForm'
+import { AddNoteForm } from '@/src/features/notes/AddNoteForm'
+import { GeneratePasswordForm } from '@/src/features/passwords/GeneratePasswordForm.jsx'
+import { SetupVault } from '@/src/features/setup/SetupVault.jsx'
+import { useOptionStore } from '@/src/store/optionStore.js'
+import { useGlobalStore } from '@/src/store/globalStore.js'
+import { useShallow } from 'zustand/react/shallow'
+import { vaultPass } from '@/src/lib/vaultPass.js'
+import { FaCopy } from 'react-icons/fa'
+import { BiExit, BiExport } from 'react-icons/bi'
+import { IoFlash } from 'react-icons/io5'
+import { FiKey, FiPlus, FiRefreshCcw, FiShare, FiUpload } from 'react-icons/fi'
+import '@/src/App.css'
+import { Loader } from './components/ui/Loader'
+import { encryptString, decryptString } from './lib/crpyto'
const bar = {
- WebkitAppRegion: "drag",
- position: "fixed",
- height: "1.8em",
- width: "100%",
- backgroundColor: "#fefff4",
+ WebkitAppRegion: 'drag',
+ position: 'fixed',
+ height: '1.8em',
+ width: '100%',
+ backgroundColor: '#fefff4',
zIndex: 1000,
- borderBottom: "1px solid var(--border)",
-};
+ borderBottom: '1px solid var(--border)'
+}
-function App() {
+function App () {
const {
vaultPassInitialized,
currentOS,
@@ -46,7 +46,7 @@ function App() {
toggleNoteForm,
isLoading,
vaultPassInv,
- setAllVaultEntries,
+ setAllVaultEntries
} = useGlobalStore(
useShallow((state) => ({
vaultPassInitialized: state.vaultPassInitialized,
@@ -59,328 +59,331 @@ function App() {
toggleNoteForm: state.toggleNoteForm,
isLoading: state.isLoading,
vaultPassInv: state.vaultPassInv,
- setAllVaultEntries: state.setAllVaultEntries,
- })),
- );
+ setAllVaultEntries: state.setAllVaultEntries
+ }))
+ )
- const [passwords, setPasswords] = React.useState([]);
- const [selectedPassword, setSelectedPassword] = React.useState(null);
- const [showSuccessAlert, setShowSuccessAlert] = React.useState(false);
- const [isShareMenuOpen, setIsShareMenuOpen] = React.useState(false);
- const [showDecryptPopup, setShowDecryptPopup] = React.useState(false);
- const [encryptedFileContent, setEncryptedFileContent] = React.useState("");
- const [roomKey, setRoomKey] = React.useState("");
- const [decryptError, setDecryptError] = React.useState("");
- const fileInputRef = React.useRef(null);
- const option = useOptionStore((state) => state.mode);
+ const [passwords, setPasswords] = React.useState([])
+ const [selectedPassword, setSelectedPassword] = React.useState(null)
+ const [showSuccessAlert, setShowSuccessAlert] = React.useState(false)
+ const [isShareMenuOpen, setIsShareMenuOpen] = React.useState(false)
+ const [showDecryptPopup, setShowDecryptPopup] = React.useState(false)
+ const [encryptedFileContent, setEncryptedFileContent] = React.useState('')
+ const [roomKey, setRoomKey] = React.useState('')
+ const [decryptError, setDecryptError] = React.useState('')
+ const fileInputRef = React.useRef(null)
+ const option = useOptionStore((state) => state.mode)
React.useEffect(() => {
const boot = async () => {
- const exists = await vaultPass.vaultExists();
+ const exists = await vaultPass.vaultExists()
if (exists) {
- await vaultPass.init();
- const savedInvCode = await vaultPass.loadInviteCode();
+ await vaultPass.init()
+ const savedInvCode = await vaultPass.loadInviteCode()
if (savedInvCode) {
- useGlobalStore.getState().setVaultPassInv(savedInvCode);
+ useGlobalStore.getState().setVaultPassInv(savedInvCode)
}
- useGlobalStore.getState().setVaultPassInitialized(true);
+ useGlobalStore.getState().setVaultPassInitialized(true)
} else {
- useGlobalStore.getState().setVaultPassInitialized(false);
- useGlobalStore.getState().setVaultPassInv(null);
+ useGlobalStore.getState().setVaultPassInitialized(false)
+ useGlobalStore.getState().setVaultPassInv(null)
}
- };
+ }
- boot();
- }, []);
+ boot()
+ }, [])
const handleExportVaultDataset = async () => {
try {
- const allEntries = await vaultPass.getAll();
+ const allEntries = await vaultPass.getAll()
const encryptedEntries = await encryptString(
JSON.stringify(allEntries),
- vaultPassInv,
- );
- setAllVaultEntries(encryptedEntries);
+ vaultPassInv
+ )
+ setAllVaultEntries(encryptedEntries)
const dataStr =
- "data:text/plain;charset=utf-8," + encodeURIComponent(encryptedEntries);
- const downloadAnchorNode = document.createElement("a");
- downloadAnchorNode.setAttribute("href", dataStr);
- downloadAnchorNode.setAttribute("download", "vault_entries.txt");
- document.body.appendChild(downloadAnchorNode);
- downloadAnchorNode.click();
- document.body.removeChild(downloadAnchorNode);
- setIsShareMenuOpen(false);
+ 'data:text/plain;charset=utf-8,' + encodeURIComponent(encryptedEntries)
+ const downloadAnchorNode = document.createElement('a')
+ downloadAnchorNode.setAttribute('href', dataStr)
+ downloadAnchorNode.setAttribute('download', 'vault_entries.txt')
+ document.body.appendChild(downloadAnchorNode)
+ downloadAnchorNode.click()
+ document.body.removeChild(downloadAnchorNode)
+ setIsShareMenuOpen(false)
} catch (e) {
- console.error("Error exporting dataset:", e);
- alert("Failed to export dataset");
+ console.error('Error exporting dataset:', e)
+ alert('Failed to export dataset')
}
- };
+ }
const handleUploadVaultDataset = async (event) => {
try {
- const file = event.target.files?.[0];
- if (!file) return;
+ const file = event.target.files?.[0]
+ if (!file) return
- const text = await file.text();
- setEncryptedFileContent(text);
- setShowDecryptPopup(true);
- setIsShareMenuOpen(false);
+ const text = await file.text()
+ setEncryptedFileContent(text)
+ setShowDecryptPopup(true)
+ setIsShareMenuOpen(false)
} catch (e) {
- console.error("Error reading file:", e);
- alert("Failed to read file");
+ console.error('Error reading file:', e)
+ alert('Failed to read file')
} finally {
- if (event.target) event.target.value = "";
+ if (event.target) event.target.value = ''
}
- };
+ }
const handleDecryptAndImport = async () => {
if (!roomKey.trim()) {
- setDecryptError("Please enter the room key");
- return;
+ setDecryptError('Please enter the room key')
+ return
}
try {
- setDecryptError("");
+ setDecryptError('')
const decryptedText = await decryptString(
encryptedFileContent,
- roomKey.trim(),
- );
- const entries = JSON.parse(decryptedText);
+ roomKey.trim()
+ )
+ const entries = JSON.parse(decryptedText)
if (!Array.isArray(entries)) {
- alert("Invalid file format. Expected a JSON array.");
- return;
+ alert('Invalid file format. Expected a JSON array.')
+ return
}
- const addedEntries = [];
+ const addedEntries = []
for (const entry of entries) {
- const { id, createdAt, updatedAt, ...data } = entry;
- await vaultPass.add(data);
- addedEntries.push(data);
+ const { id, createdAt, updatedAt, ...data } = entry
+ await vaultPass.add(data)
+ addedEntries.push(data)
}
- useGlobalStore.getState().triggerRefreshPasswords();
- useGlobalStore.getState().triggerRefreshNotes();
- setShowDecryptPopup(false);
- setEncryptedFileContent("");
- setRoomKey("");
+ useGlobalStore.getState().triggerRefreshPasswords()
+ useGlobalStore.getState().triggerRefreshNotes()
+ setShowDecryptPopup(false)
+ setEncryptedFileContent('')
+ setRoomKey('')
} catch (e) {
- console.error("Error decrypting/importing dataset:", e);
- setDecryptError("Invalid room key or corrupted file. Please try again.");
+ console.error('Error decrypting/importing dataset:', e)
+ setDecryptError('Invalid room key or corrupted file. Please try again.')
}
- };
+ }
const handleCancelDecrypt = () => {
- setShowDecryptPopup(false);
- setEncryptedFileContent("");
- setRoomKey("");
- setDecryptError("");
- };
+ setShowDecryptPopup(false)
+ setEncryptedFileContent('')
+ setRoomKey('')
+ setDecryptError('')
+ }
const handleExitVault = async () => {
try {
- await vaultPass.resetVault();
- useGlobalStore.getState().setVaultPassInitialized(false);
- useGlobalStore.getState().setVaultPassInv(null);
+ await vaultPass.resetVault()
+ useGlobalStore.getState().setVaultPassInitialized(false)
+ useGlobalStore.getState().setVaultPassInv(null)
} catch (e) {
- console.error("Error resetting vault:", e);
- alert("Failed to reset vault");
+ console.error('Error resetting vault:', e)
+ alert('Failed to reset vault')
}
- };
+ }
const handleSelectPassword = (password) => {
- setSelectedPassword(password);
- };
+ setSelectedPassword(password)
+ }
const handleDeletePassword = async (id) => {
try {
- await vaultPass.delete(id);
- setPasswords((prev) => prev.filter((pass) => pass.id !== id));
+ await vaultPass.delete(id)
+ setPasswords((prev) => prev.filter((pass) => pass.id !== id))
} catch (e) {
- console.error("Error deleting password:", e);
+ console.error('Error deleting password:', e)
}
- };
+ }
const handleCloseSidebar = () => {
- setSelectedPassword(null);
- };
+ setSelectedPassword(null)
+ }
const copyInvCode = async () => {
try {
- await navigator.clipboard.writeText(vaultPassInv);
- setShowSuccessAlert(true);
+ await navigator.clipboard.writeText(vaultPassInv)
+ setShowSuccessAlert(true)
} catch (e) {
- console.error("Error copying invite code:", e);
- alert("Failed to copy invite code");
+ console.error('Error copying invite code:', e)
+ alert('Failed to copy invite code')
}
- };
+ }
const applicationReload = () => {
- useGlobalStore.getState().setIsLoading(true);
- window.location.reload();
- };
+ useGlobalStore.getState().setIsLoading(true)
+ window.location.reload()
+ }
if (!vaultPassInitialized || vaultPass === null) {
- return ;
+ return
}
- return !vaultPassInitialized && vaultPass === null ? (
-
- ) : (
-
- {showSuccessAlert && (
-
}
- title="Success!"
- message="Invite code
- copied to clipboard!"
- onClose={() => setShowSuccessAlert(false)}
- />
- )}
-
-
-
- VAULT
-
-
-
- End-to-End Encrypted
+ return !vaultPassInitialized && vaultPass === null
+ ? (
+
+ )
+ : (
+
+ {showSuccessAlert && (
+
}
+ title='Success!'
+ message='Invite code
+ copied to clipboard!'
+ onClose={() => setShowSuccessAlert(false)}
+ />
+ )}
+
+
+
+ VAULT
+
+
+
+ End-to-End Encrypted
+
-
-
-
- {isLoading &&
}
-
-
+ {isLoading &&
}
+
+
-
-
-
-
-
+ >
+ )}
-
- {option === "password" ? (
-
- ) : (
-
- )}
- {isPasswordFormActive && (
- <>
-
-
- >
- )}
- {isGenerateFormActive && (
- <>
-
-
- >
- )}
- {isNoteFormActive && (
- <>
-
-
- >
- )}
- {showDecryptPopup && (
- <>
-
-
- >
- )}
-
- );
+ )
}
-createRoot(document.getElementById("root")).render();
+createRoot(document.getElementById('root')).render()
diff --git a/src/components/layout/Overlay.jsx b/src/components/layout/Overlay.jsx
index fa07d13..6c63788 100644
--- a/src/components/layout/Overlay.jsx
+++ b/src/components/layout/Overlay.jsx
@@ -1,6 +1,6 @@
-import React from "react";
-import { useGlobalStore } from "@/src/store/globalStore.js";
-import { useShallow } from "zustand/react/shallow";
+import React from 'react'
+import { useGlobalStore } from '@/src/store/globalStore.js'
+import { useShallow } from 'zustand/react/shallow'
export const Overlay = React.memo(() => {
const {
@@ -11,7 +11,7 @@ export const Overlay = React.memo(() => {
isPasswordFormActive,
isGenerateFormActive,
isNoteFormActive,
- isAllEnteriesPopupActive,
+ isAllEnteriesPopupActive
} = useGlobalStore(
useShallow((state) => ({
togglePasswordForm: state.togglePasswordForm,
@@ -21,16 +21,16 @@ export const Overlay = React.memo(() => {
isPasswordFormActive: state.isPasswordFormActive,
isGenerateFormActive: state.isGenerateFormActive,
isNoteFormActive: state.isNoteFormActive,
- isAllEnteriesPopupActive: state.isAllEnteriesPopupActive,
- })),
- );
+ isAllEnteriesPopupActive: state.isAllEnteriesPopupActive
+ }))
+ )
const handleOverlayClick = () => {
- isPasswordFormActive && togglePasswordForm();
- isGenerateFormActive && toggleGenerateForm();
- isNoteFormActive && toggleNoteForm();
- isAllEnteriesPopupActive && toggleAllEnteriesPopup();
- };
+ isPasswordFormActive && togglePasswordForm()
+ isGenerateFormActive && toggleGenerateForm()
+ isNoteFormActive && toggleNoteForm()
+ isAllEnteriesPopupActive && toggleAllEnteriesPopup()
+ }
- return ;
-});
+ return
+})
diff --git a/src/components/layout/SideBar.jsx b/src/components/layout/SideBar.jsx
index 383747b..eb61dac 100644
--- a/src/components/layout/SideBar.jsx
+++ b/src/components/layout/SideBar.jsx
@@ -1,264 +1,263 @@
/* global alert */
-import React, { useState } from "react";
-import { FiX, FiTrash2, FiEdit, FiSave } from "react-icons/fi";
-import { timeAgo } from "@/src/utils/timeAgo";
-import PasswordInput from "../password/PasswordInput.jsx";
-import { Input } from "@/src/components/ui/Input.jsx";
-import { Button } from "@/src/components/ui/Button.jsx";
-import { Tag } from "@/src/components/ui/Tag.jsx";
-import "@/src/App.css";
-import { vaultPass } from "@/src/lib/vaultPass.js";
-import { useGlobalStore } from "@/src/store/globalStore.js";
-import Alert from "@/src/components/popups/Alert.jsx";
-import { FaCheckCircle } from "react-icons/fa";
+import React, { useState } from 'react'
+import { FiX, FiTrash2, FiEdit, FiSave } from 'react-icons/fi'
+import { timeAgo } from '@/src/utils/timeAgo'
+import PasswordInput from '../password/PasswordInput.jsx'
+import { Input } from '@/src/components/ui/Input.jsx'
+import { Button } from '@/src/components/ui/Button.jsx'
+import { Tag } from '@/src/components/ui/Tag.jsx'
+import '@/src/App.css'
+import { vaultPass } from '@/src/lib/vaultPass.js'
+import { useGlobalStore } from '@/src/store/globalStore.js'
+import Alert from '@/src/components/popups/Alert.jsx'
+import { FaCheckCircle } from 'react-icons/fa'
export const SideBar = ({ password, onClose, onDelete }) => {
- const PREDEFINED_TAGS = ["work", "personal"];
- if (!password) return null;
+ const PREDEFINED_TAGS = ['work', 'personal']
+ if (!password) return null
- const normalizeTag = (tag) => tag.trim().toLowerCase();
+ const normalizeTag = (tag) => tag.trim().toLowerCase()
- const [isEditMode, setIsEditMode] = useState(false);
- const [newName, setNewName] = useState(password.name);
- const [newWebsite, setNewWebsite] = useState(password.website);
- const [newUsername, setNewUsername] = useState(password.username);
- const [newPassword, setNewPassword] = useState(password.password);
+ const [isEditMode, setIsEditMode] = useState(false)
+ const [newName, setNewName] = useState(password.name)
+ const [newWebsite, setNewWebsite] = useState(password.website)
+ const [newUsername, setNewUsername] = useState(password.username)
+ const [newPassword, setNewPassword] = useState(password.password)
const [newTag, setNewTag] = useState(
- password.tag ? normalizeTag(password.tag) : "",
- );
- const [tagInput, setTagInput] = useState("");
- const [showTagSuggestions, setShowTagSuggestions] = useState(false);
- const [customTags, setCustomTags] = useState([]);
- const [showSuccessAlert, setShowSuccessAlert] = useState(false);
+ password.tag ? normalizeTag(password.tag) : ''
+ )
+ const [tagInput, setTagInput] = useState('')
+ const [showTagSuggestions, setShowTagSuggestions] = useState(false)
+ const [customTags, setCustomTags] = useState([])
+ const [showSuccessAlert, setShowSuccessAlert] = useState(false)
React.useEffect(() => {
const fetchExistingTags = async () => {
try {
- const entries = await vaultPass.getAll();
+ const entries = await vaultPass.getAll()
const allTags = entries
.map((entry) => entry.tag)
.filter((tag) => tag)
.map(normalizeTag)
.filter((tag) => tag && !PREDEFINED_TAGS.includes(tag))
- .filter((tag, index, self) => self.indexOf(tag) === index);
- setCustomTags(allTags);
+ .filter((tag, index, self) => self.indexOf(tag) === index)
+ setCustomTags(allTags)
} catch (error) {
- console.error("Error fetching tags:", error);
+ console.error('Error fetching tags:', error)
}
- };
+ }
if (isEditMode) {
- fetchExistingTags();
+ fetchExistingTags()
}
- }, [isEditMode]);
+ }, [isEditMode])
const handleTagInput = (value) => {
- setTagInput(value);
- if (value.startsWith("/")) {
- setShowTagSuggestions(true);
+ setTagInput(value)
+ if (value.startsWith('/')) {
+ setShowTagSuggestions(true)
} else {
- setShowTagSuggestions(false);
+ setShowTagSuggestions(false)
}
- };
+ }
const handleSelectTag = (tag) => {
- setNewTag(normalizeTag(tag));
- setTagInput("");
- setShowTagSuggestions(false);
- };
+ setNewTag(normalizeTag(tag))
+ setTagInput('')
+ setShowTagSuggestions(false)
+ }
const handleRemoveTag = () => {
- setNewTag("");
- setTagInput("");
- };
+ setNewTag('')
+ setTagInput('')
+ }
const getFilteredTags = () => {
- const input = normalizeTag(tagInput.replace("/", ""));
+ const input = normalizeTag(tagInput.replace('/', ''))
const allAvailableTags = [...PREDEFINED_TAGS, ...customTags].map(
- normalizeTag,
- );
+ normalizeTag
+ )
return allAvailableTags.filter(
- (tag) => tag.toLowerCase().includes(input) && tag !== newTag,
- );
- };
+ (tag) => tag.toLowerCase().includes(input) && tag !== newTag
+ )
+ }
const handleKeyDownTag = (e) => {
- if (e.key === "Enter" && tagInput.startsWith("/")) {
- e.preventDefault();
- const customTag = normalizeTag(tagInput.slice(1));
+ if (e.key === 'Enter' && tagInput.startsWith('/')) {
+ e.preventDefault()
+ const customTag = normalizeTag(tagInput.slice(1))
if (customTag) {
- handleSelectTag(customTag);
+ handleSelectTag(customTag)
}
}
- };
+ }
const handleSaveChanges = async () => {
try {
const editEntry = {
id: password.id,
- type: "password",
+ type: 'password',
name: newName,
website: newWebsite,
username: newUsername,
password: newPassword,
- tag: newTag ? normalizeTag(newTag) : "",
+ tag: newTag ? normalizeTag(newTag) : '',
createdAt: password.createdAt,
- editedAt: new Date().toISOString(),
- };
- await vaultPass.edit(password.id, editEntry);
- setIsEditMode(false);
- setShowSuccessAlert(true);
- useGlobalStore.getState().triggerRefreshPasswords();
+ editedAt: new Date().toISOString()
+ }
+ await vaultPass.edit(password.id, editEntry)
+ setIsEditMode(false)
+ setShowSuccessAlert(true)
+ useGlobalStore.getState().triggerRefreshPasswords()
setTimeout(() => {
- setShowSuccessAlert(false);
- onClose();
- }, 2000);
+ setShowSuccessAlert(false)
+ onClose()
+ }, 2000)
} catch (error) {
- console.error("Error updating password:", error);
- alert("Failed to update password");
+ console.error('Error updating password:', error)
+ alert('Failed to update password')
}
- };
+ }
const handleCancel = () => {
- setNewName(password.name);
- setNewWebsite(password.website);
- setNewUsername(password.username);
- setNewPassword(password.password);
- setNewTag(password.tag ? normalizeTag(password.tag) : "");
- setTagInput("");
- setShowTagSuggestions(false);
- setIsEditMode(false);
- };
+ setNewName(password.name)
+ setNewWebsite(password.website)
+ setNewUsername(password.username)
+ setNewPassword(password.password)
+ setNewTag(password.tag ? normalizeTag(password.tag) : '')
+ setTagInput('')
+ setShowTagSuggestions(false)
+ setIsEditMode(false)
+ }
return (
<>
{showSuccessAlert && (
}
- color="var(--text-jetBrains)"
- title="Success!"
- message="Password updated successfully."
+ color='var(--text-jetBrains)'
+ title='Success!'
+ message='Password updated successfully.'
onClose={() => setShowSuccessAlert(false)}
/>
)}
-
e.stopPropagation()}>
-
+
e.stopPropagation()}>
+
{newName}
-
-
-
+
+
setNewUsername(e.target.value)}
- label="Username"
- placeholder="Enter username"
+ label='Username'
+ placeholder='Enter username'
/>
-
+
setNewWebsite(e.target.value)}
- label="Website"
- placeholder="Enter website"
+ label='Website'
+ placeholder='Enter website'
/>
-
+
setNewPassword(e.target.value)}
- label="Password"
- placeholder="Enter password"
+ label='Password'
+ placeholder='Enter password'
/>
-
+
-
+
handleTagInput(e.target.value)}
onKeyDown={handleKeyDownTag}
- label=""
- placeholder="Type /work or /personal (or custom)"
+ label=''
+ placeholder='Type /work or /personal (or custom)'
/>
- {showTagSuggestions && tagInput.startsWith("/") && (
-
+ {showTagSuggestions && tagInput.startsWith('/') && (
+
{getFilteredTags().length > 0
? getFilteredTags().map((tag) => (
-
handleSelectTag(tag)}
- className="dropdown-list"
- >
- /{tag}
- {!PREDEFINED_TAGS.includes(tag) && (
-
- (custom)
-
- )}
-
- ))
+
handleSelectTag(tag)}
+ className='dropdown-list'
+ >
+ /{tag}
+ {!PREDEFINED_TAGS.includes(tag) && (
+
+ (custom)
+
+ )}
+
+ ))
: null}
{normalizeTag(tagInput.slice(1)) &&
![...PREDEFINED_TAGS, ...customTags]
.map(normalizeTag)
.includes(normalizeTag(tagInput.slice(1))) && (
-
- handleSelectTag(normalizeTag(tagInput.slice(1)))
- }
- className="dropdown-list"
- style={{ fontStyle: "italic", opacity: 0.8 }}
- >
- Create tag: /{normalizeTag(tagInput.slice(1))}
-
- )}
+
+ handleSelectTag(normalizeTag(tagInput.slice(1)))}
+ className='dropdown-list'
+ style={{ fontStyle: 'italic', opacity: 0.8 }}
+ >
+ Create tag: /{normalizeTag(tagInput.slice(1))}
+
+ )}
)}
{newTag && (
@@ -268,54 +267,56 @@ export const SideBar = ({ password, onClose, onDelete }) => {
-
+
Created {timeAgo(password.createdAt)}
-
- {!isEditMode ? (
- <>
-
onDelete(password.id)}
- />
- setIsEditMode(true)}
- style={{
- color: "var(--text-dark)",
- backgroundColor: "#C8F03E",
- width: "100%",
- }}
- />
- >
- ) : (
- <>
-
-
- >
- )}
+
+ {!isEditMode
+ ? (
+ <>
+ onDelete(password.id)}
+ />
+ setIsEditMode(true)}
+ style={{
+ color: 'var(--text-dark)',
+ backgroundColor: '#C8F03E',
+ width: '100%'
+ }}
+ />
+ >
+ )
+ : (
+ <>
+
+
+ >
+ )}
>
- );
-};
+ )
+}
diff --git a/src/components/menu/ShortMenu.jsx b/src/components/menu/ShortMenu.jsx
index 4674b1a..5a3e71e 100644
--- a/src/components/menu/ShortMenu.jsx
+++ b/src/components/menu/ShortMenu.jsx
@@ -1,59 +1,59 @@
-import React from "react";
+import React from 'react'
export const SortMenu = ({ sortOrder, setSortOrder, setShowSortMenu }) => {
const options = [
- { value: "latest", label: "Newest First" },
- { value: "oldest", label: "Oldest First" },
- { value: "aToZ", label: "Name (A to Z)" },
- { value: "zToA", label: "Name (Z to A)" },
- ];
+ { value: 'latest', label: 'Newest First' },
+ { value: 'oldest', label: 'Oldest First' },
+ { value: 'aToZ', label: 'Name (A to Z)' },
+ { value: 'zToA', label: 'Name (Z to A)' }
+ ]
return (
-
+
{options.map((option) => (
{
- setSortOrder(option.value);
- setShowSortMenu(false);
+ setSortOrder(option.value)
+ setShowSortMenu(false)
}}
- className="dropdown-list"
- style={{ fontSize: "14px" }}
+ className='dropdown-list'
+ style={{ fontSize: '14px' }}
>
{option.label}
))}
- );
-};
+ )
+}
export const getSortLabel = (order) => {
switch (order) {
- case "aToZ":
- return "Name (A to Z)";
- case "zToA":
- return "Name (Z to A)";
- case "latest":
- return "Newest First";
- case "oldest":
- return "Oldest First";
+ case 'aToZ':
+ return 'Name (A to Z)'
+ case 'zToA':
+ return 'Name (Z to A)'
+ case 'latest':
+ return 'Newest First'
+ case 'oldest':
+ return 'Oldest First'
default:
- return "Sort by";
+ return 'Sort by'
}
-};
+}
export const sortPasswords = (passwords, order) => {
return [...passwords].sort((a, b) => {
switch (order) {
- case "aToZ":
- return (a.name || "").localeCompare(b.name || "");
- case "zToA":
- return (b.name || "").localeCompare(a.name || "");
- case "oldest":
- return a.createdAt - b.createdAt;
- case "latest":
+ case 'aToZ':
+ return (a.name || '').localeCompare(b.name || '')
+ case 'zToA':
+ return (b.name || '').localeCompare(a.name || '')
+ case 'oldest':
+ return a.createdAt - b.createdAt
+ case 'latest':
default:
- return b.createdAt - a.createdAt;
+ return b.createdAt - a.createdAt
}
- });
-};
+ })
+}
diff --git a/src/components/notes/NoteCard.jsx b/src/components/notes/NoteCard.jsx
index eb6bb76..4c363da 100644
--- a/src/components/notes/NoteCard.jsx
+++ b/src/components/notes/NoteCard.jsx
@@ -1,75 +1,75 @@
-import React from "react";
-import { Divider } from "@/src/components/ui/Divider.jsx";
-import { timeAgo } from "@/src/utils/timeAgo.js";
-import { FiFileText, FiTrash } from "react-icons/fi";
-import "@/src/App.css";
+import React from 'react'
+import { Divider } from '@/src/components/ui/Divider.jsx'
+import { timeAgo } from '@/src/utils/timeAgo.js'
+import { FiFileText, FiTrash } from 'react-icons/fi'
+import '@/src/App.css'
export const NoteCard = ({ data, onDelete, onClick }) => {
const title =
- data?.content?.find((item) => item.type === "title")?.content || null;
+ data?.content?.find((item) => item.type === 'title')?.content || null
const preview =
data?.content
- ?.filter((item) => item.type !== "title")
+ ?.filter((item) => item.type !== 'title')
?.map((item) => item.content)
- ?.join(" ")
- ?.substring(0, 100) + "..." || "No content";
+ ?.join(' ')
+ ?.substring(0, 100) + '...' || 'No content'
return (
-
-
+
+
-
+
-
- {title && {title}
}
+
+ {title && {title}
}
{preview}
{
- e.stopPropagation();
- onDelete();
+ e.stopPropagation()
+ onDelete()
}}
>
-
+
-
+
-
+
{timeAgo(data.createdAt)}
- );
-};
+ )
+}
diff --git a/src/components/notes/NoteSideBar.jsx b/src/components/notes/NoteSideBar.jsx
index 9614547..6e6ee5d 100644
--- a/src/components/notes/NoteSideBar.jsx
+++ b/src/components/notes/NoteSideBar.jsx
@@ -1,121 +1,123 @@
-import React, { useState } from "react";
-import { FiX, FiTrash2, FiEdit, FiSave } from "react-icons/fi";
-import { timeAgo } from "@/src/utils/timeAgo";
-import { Button } from "@/src/components/ui/Button.jsx";
-import { Input } from "@/src/components/ui/Input.jsx";
-import "@/src/App.css";
-import { vaultPass } from "@/src/lib/vaultPass.js";
-import { useGlobalStore } from "@/src/store/globalStore.js";
-import Alert from "@/src/components/popups/Alert.jsx";
+import React, { useState } from 'react'
+import { FiX, FiTrash2, FiEdit, FiSave } from 'react-icons/fi'
+import { timeAgo } from '@/src/utils/timeAgo'
+import { Button } from '@/src/components/ui/Button.jsx'
+import { Input } from '@/src/components/ui/Input.jsx'
+import '@/src/App.css'
+import { vaultPass } from '@/src/lib/vaultPass.js'
+import { useGlobalStore } from '@/src/store/globalStore.js'
+import Alert from '@/src/components/popups/Alert.jsx'
export const NoteSideBar = ({ note, onClose, onDelete }) => {
- if (!note) return null;
+ if (!note) return null
- const [isEditMode, setIsEditMode] = useState(false);
- const [showSuccessAlert, setShowSuccessAlert] = useState(false);
- const [searchQuery, setSearchQuery] = useState("");
+ const [isEditMode, setIsEditMode] = useState(false)
+ const [showSuccessAlert, setShowSuccessAlert] = useState(false)
+ const [searchQuery, setSearchQuery] = useState('')
React.useEffect(() => {
const fetchExistingTags = async () => {
try {
- await vaultPass.getAll();
+ await vaultPass.getAll()
} catch (error) {
- console.error("Error fetching tags:", error);
+ console.error('Error fetching tags:', error)
}
- };
+ }
if (isEditMode) {
- fetchExistingTags();
+ fetchExistingTags()
}
- }, [isEditMode]);
+ }, [isEditMode])
const handleSaveEdit = async () => {
try {
const updatedNote = {
- ...note,
- };
- await vaultPass.update(note.id, updatedNote);
- setIsEditMode(false);
- setShowSuccessAlert(true);
- setTimeout(() => setShowSuccessAlert(false), 2000);
- useGlobalStore.getState().triggerRefreshNotes?.();
+ ...note
+ }
+ await vaultPass.update(note.id, updatedNote)
+ setIsEditMode(false)
+ setShowSuccessAlert(true)
+ setTimeout(() => setShowSuccessAlert(false), 2000)
+ useGlobalStore.getState().triggerRefreshNotes?.()
} catch (error) {
- console.error("Error updating note:", error);
+ console.error('Error updating note:', error)
}
- };
+ }
- const normalizedQuery = searchQuery.trim().toLowerCase();
+ const normalizedQuery = searchQuery.trim().toLowerCase()
const filteredContent = normalizedQuery
? note?.content?.filter((item) =>
- item?.content?.toLowerCase().includes(normalizedQuery),
- )
- : note?.content;
+ item?.content?.toLowerCase().includes(normalizedQuery)
+ )
+ : note?.content
- const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const highlightMatch = (text) => {
- if (!normalizedQuery || !text) return text;
- const regex = new RegExp(`(${escapeRegExp(normalizedQuery)})`, "ig");
- const parts = text.split(regex);
+ if (!normalizedQuery || !text) return text
+ const regex = new RegExp(`(${escapeRegExp(normalizedQuery)})`, 'ig')
+ const parts = text.split(regex)
return parts.map((part, index) =>
- regex.test(part) ? (
-
- {part}
-
- ) : (
-
{part}
- ),
- );
- };
+ regex.test(part)
+ ? (
+
+ {part}
+
+ )
+ : (
+
{part}
+ )
+ )
+ }
return (
<>
{showSuccessAlert && (
-
+
)}
-
e.stopPropagation()}>
+
e.stopPropagation()}>
{/* Header */}
-
+
{timeAgo(note.createdAt)}
-
-
+
+
{/* Note Content */}
-
+
setSearchQuery(e.target.value)}
/>
{filteredContent?.map((item, idx) => (
- {item.type === "title" && (
-
+ {item.type === 'title' && (
+
{highlightMatch(item.content)}
)}
- {item.type === "subtitle" && (
-
+ {item.type === 'subtitle' && (
+
{highlightMatch(item.content)}
)}
- {item.type === "para" && (
-
+ {item.type === 'para' && (
+
{highlightMatch(item.content)}
)}
@@ -124,44 +126,46 @@ export const NoteSideBar = ({ note, onClose, onDelete }) => {
{/* Action Buttons */}
-
+
onDelete(note.id)}
/>
- {!isEditMode ? (
- setIsEditMode(true)}
- style={{
- color: "var(--text-dark)",
- backgroundColor: "#C8F03E",
- width: "100%",
- }}
- />
- ) : (
-
- )}
+ {!isEditMode
+ ? (
+ setIsEditMode(true)}
+ style={{
+ color: 'var(--text-dark)',
+ backgroundColor: '#C8F03E',
+ width: '100%'
+ }}
+ />
+ )
+ : (
+
+ )}
>
- );
-};
+ )
+}
diff --git a/src/components/password/PasswordCard.jsx b/src/components/password/PasswordCard.jsx
index 3880ed1..9e17809 100644
--- a/src/components/password/PasswordCard.jsx
+++ b/src/components/password/PasswordCard.jsx
@@ -1,88 +1,88 @@
-import React from "react";
-import { Divider } from "@/src/components/ui/Divider.jsx";
-import PasswordInput from "@/src/components/password/PasswordInput.jsx";
-import { Tag } from "@/src/components/ui/Tag.jsx";
-import { timeAgo } from "@/src/utils/timeAgo.js";
-import { FiLock, FiTrash } from "react-icons/fi";
-import "@/src/App.css";
+import React from 'react'
+import { Divider } from '@/src/components/ui/Divider.jsx'
+import PasswordInput from '@/src/components/password/PasswordInput.jsx'
+import { Tag } from '@/src/components/ui/Tag.jsx'
+import { timeAgo } from '@/src/utils/timeAgo.js'
+import { FiLock, FiTrash } from 'react-icons/fi'
+import '@/src/App.css'
export const PasswordCard = ({ data, onDelete, onClick }) => {
- const title = data?.name || "Untitled";
- const website = data?.website || "No website";
- const username = data?.username || "No username";
- const password = data?.password || "";
- const tags = data?.tag || [];
+ const title = data?.name || 'Untitled'
+ const website = data?.website || 'No website'
+ const username = data?.username || 'No username'
+ const password = data?.password || ''
+ const tags = data?.tag || []
return (
-
-
+
+
-
+
-
- {title}
+
+ {title}
{website}
{
- e.stopPropagation();
- onDelete();
+ e.stopPropagation()
+ onDelete()
}}
>
-
+
-
{username}
-
+
{username}
+
-
+
{tags.length > 0 && (
-
-
+
+
)}
-
+
{/*
*/}
{timeAgo(data.createdAt)}
- );
-};
+ )
+}
diff --git a/src/components/password/PasswordInput.jsx b/src/components/password/PasswordInput.jsx
index dbf4204..803d6a8 100644
--- a/src/components/password/PasswordInput.jsx
+++ b/src/components/password/PasswordInput.jsx
@@ -1,82 +1,84 @@
-import React, { useState } from "react";
-import { FiCopy, FiEye, FiEyeOff } from "react-icons/fi";
+import React, { useState } from 'react'
+import { FiCopy, FiEye, FiEyeOff } from 'react-icons/fi'
const PasswordInput = ({
value,
onChange,
- placeholder = "Enter password",
- label = null,
+ placeholder = 'Enter password',
+ label = null
}) => {
- const [showPassword, setShowPassword] = useState(false);
- const [copied, setCopied] = useState(false);
+ const [showPassword, setShowPassword] = useState(false)
+ const [copied, setCopied] = useState(false)
const togglePassword = () => {
- setShowPassword((prev) => !prev);
- };
+ setShowPassword((prev) => !prev)
+ }
const copyPassword = async () => {
- if (!value) return;
+ if (!value) return
try {
- await navigator.clipboard.writeText(value);
- setCopied(true);
- setTimeout(() => setCopied(false), 1500);
+ await navigator.clipboard.writeText(value)
+ setCopied(true)
+ setTimeout(() => setCopied(false), 1500)
} catch (err) {
- console.error("Failed to copy:", err);
+ console.error('Failed to copy:', err)
}
- };
+ }
return (
<>
{label !== null && (
)}
-
+
{
- e.stopPropagation();
- togglePassword();
+ e.stopPropagation()
+ togglePassword()
}}
- className="iconBtn neu_border"
- style={{ right: "40px" }}
+ className='iconBtn neu_border'
+ style={{ right: '40px' }}
>
- {showPassword ? (
-
- ) : (
-
- )}
+ {showPassword
+ ? (
+
+ )
+ : (
+
+ )}
{
- e.stopPropagation();
- copyPassword();
+ e.stopPropagation()
+ copyPassword()
}}
- className="iconBtn neu_border"
- style={{ right: "10px" }}
+ className='iconBtn neu_border'
+ style={{ right: '10px' }}
>
-
+
- {copied && Copied!}
+ {copied && Copied!}
>
- );
-};
+ )
+}
-export default PasswordInput;
+export default PasswordInput
diff --git a/src/components/password/Search.jsx b/src/components/password/Search.jsx
index 24201f2..3dd2fdd 100644
--- a/src/components/password/Search.jsx
+++ b/src/components/password/Search.jsx
@@ -1,44 +1,44 @@
-import React, { useEffect, useRef } from "react";
+import React, { useEffect, useRef } from 'react'
-export const Search = ({ content = "Search...", value, onChange }) => {
- const inputRef = useRef(null);
+export const Search = ({ content = 'Search...', value, onChange }) => {
+ const inputRef = useRef(null)
useEffect(() => {
const handleKeyDown = (e) => {
- if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
- e.preventDefault();
- inputRef.current?.focus();
+ if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
+ e.preventDefault()
+ inputRef.current?.focus()
}
- };
+ }
- window.addEventListener("keydown", handleKeyDown);
- return () => window.removeEventListener("keydown", handleKeyDown);
- }, []);
+ window.addEventListener('keydown', handleKeyDown)
+ return () => window.removeEventListener('keydown', handleKeyDown)
+ }, [])
return (
-
+
- ⌘K
+ ⌘K
- );
-};
+ )
+}
diff --git a/src/components/popups/Alert.jsx b/src/components/popups/Alert.jsx
index 24f3d5a..bbbef05 100644
--- a/src/components/popups/Alert.jsx
+++ b/src/components/popups/Alert.jsx
@@ -1,53 +1,53 @@
-import React, { useEffect, useState } from "react";
-import { FiX } from "react-icons/fi";
-import "@/src/App.css";
+import React, { useEffect, useState } from 'react'
+import { FiX } from 'react-icons/fi'
+import '@/src/App.css'
-export default function Alert({
+export default function Alert ({
icon,
- color = "#4f46e5",
+ color = '#4f46e5',
title,
message,
duration = 4000,
- onClose,
+ onClose
}) {
- const [visible, setVisible] = useState(false);
+ const [visible, setVisible] = useState(false)
useEffect(() => {
- setVisible(true);
+ setVisible(true)
if (duration) {
const timer = setTimeout(() => {
- handleClose();
- }, duration);
+ handleClose()
+ }, duration)
- return () => clearTimeout(timer);
+ return () => clearTimeout(timer)
}
- }, []);
+ }, [])
const handleClose = () => {
- setVisible(false);
+ setVisible(false)
setTimeout(() => {
- onClose && onClose();
- }, 300);
- };
+ onClose && onClose()
+ }, 300)
+ }
return (
-
+
{icon}
-
-
{title}
-
{message}
+
-
-
+
+
- );
+ )
}
diff --git a/src/components/popups/DecryptPopUp.jsx b/src/components/popups/DecryptPopUp.jsx
index 23629b2..85023e2 100644
--- a/src/components/popups/DecryptPopUp.jsx
+++ b/src/components/popups/DecryptPopUp.jsx
@@ -1,70 +1,70 @@
-import React from "react";
-import { FiX, FiUpload } from "react-icons/fi";
-import { Input } from "@/src/components/ui/Input.jsx";
-import { Button } from "@/src/components/ui/Button.jsx";
-import "@/src/App.css";
+import React from 'react'
+import { FiX, FiUpload } from 'react-icons/fi'
+import { Input } from '@/src/components/ui/Input.jsx'
+import { Button } from '@/src/components/ui/Button.jsx'
+import '@/src/App.css'
export const DecryptPopUp = ({
roomKey,
setRoomKey,
decryptError,
handleDecryptAndImport,
- handleCancelDecrypt,
+ handleCancelDecrypt
}) => {
return (
-