Update browser extension UI, standardize font sizes (#1197)

This commit is contained in:
Leendert de Borst
2025-09-11 13:42:21 +02:00
committed by Leendert de Borst
parent adc0e8227f
commit fe78524e41
27 changed files with 174 additions and 93 deletions

View File

@@ -108,6 +108,4 @@ async function extendAutoLockTimer(): Promise<void> {
console.error('[AUTO_LOCK] Error locking vault:', error);
}
}, timeout * 1000);
console.info(`[AUTO_LOCK] Timer extended (popup heartbeat)`);
}

View File

@@ -167,7 +167,7 @@ const EmailDomainField: React.FC<EmailDomainFieldProps> = ({
return (
<div className="space-y-2">
<label htmlFor={id} className="block text-sm font-medium text-gray-700 dark:text-gray-300">
<label htmlFor={id} className="block font-medium text-gray-700 dark:text-gray-300">
{label}
{required && <span className="text-red-500 ml-1">*</span>}
</label>
@@ -177,7 +177,7 @@ const EmailDomainField: React.FC<EmailDomainFieldProps> = ({
<input
type="text"
id={id}
className={`flex-1 min-w-0 px-3 py-2 border ${
className={`flex-1 min-w-0 px-3 py-2 border text-sm ${
error ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
} ${
!isCustomDomain ? 'rounded-l-md' : 'rounded-md'
@@ -209,9 +209,9 @@ const EmailDomainField: React.FC<EmailDomainFieldProps> = ({
{showPrivateDomains && (
<div className="mb-4">
<h4 className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
{t('credentials.privateEmailTitle')} <span className="text-xs text-gray-500 dark:text-gray-400">({t('credentials.privateEmailAliasVaultServer')})</span>
{t('credentials.privateEmailTitle')} <span className="text-gray-500 dark:text-gray-400">({t('credentials.privateEmailAliasVaultServer')})</span>
</h4>
<p className="text-xs text-gray-500 dark:text-gray-400 mb-3">
<p className="text-gray-500 dark:text-gray-400 mb-3">
{t('credentials.privateEmailDescription')}
</p>
<div className="flex flex-wrap gap-2">

View File

@@ -213,7 +213,7 @@ export const EmailPreview: React.FC<EmailPreviewProps> = ({ email }) => {
}
if (emails.length === 0) {
return (
<div className="text-gray-500 dark:text-gray-400 mb-4">
<div className="text-gray-500 dark:text-gray-400 mb-4 text-sm">
<div className="flex items-center gap-2 mb-2">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">{t('common.recentEmails')}</h2>
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse" />

View File

@@ -109,7 +109,7 @@ export const FormInput = forwardRef<HTMLInputElement, FormInputProps>(({
}
};
const inputClasses = `mt-1 block w-full rounded-md ${
const inputClasses = `mt-1 block text-sm w-full rounded-md ${
error ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
} text-gray-900 sm:text-sm rounded-lg shadow-sm border focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:placeholder-gray-400 py-2 px-3`;

View File

@@ -82,7 +82,7 @@ export const FormInputCopyToClipboard: React.FC<FormInputCopyToClipboardProps> =
try {
await navigator.clipboard.writeText(value);
clipboardService.setCopied(id);
// Notify background script that clipboard was copied
await sendMessage('CLIPBOARD_COPIED', { value }, 'background');
@@ -111,7 +111,7 @@ export const FormInputCopyToClipboard: React.FC<FormInputCopyToClipboardProps> =
onClick={copyToClipboard}
className={`w-full px-3 py-2.5 bg-white border ${
copied ? 'border-green-500 border-2' : 'border-gray-300'
} text-gray-900 sm:text-sm rounded-lg shadow-sm focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:placeholder-gray-400`}
} text-gray-900 text-sm rounded-lg shadow-sm focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:placeholder-gray-400`}
/>
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-2">
{copied ? (

View File

@@ -62,7 +62,7 @@ const BottomNav: React.FC = () => {
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
</svg>
<span className="text-xs mt-1">{t('menu.credentials')}</span>
<span className="text-sm mt-1">{t('menu.credentials')}</span>
</button>
<button
onClick={() => handleTabChange('emails')}
@@ -73,7 +73,7 @@ const BottomNav: React.FC = () => {
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
<span className="text-xs mt-1">{t('menu.emails')}</span>
<span className="text-sm mt-1">{t('menu.emails')}</span>
</button>
<button
onClick={() => handleTabChange('settings')}
@@ -85,7 +85,7 @@ const BottomNav: React.FC = () => {
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<span className="text-xs mt-1">{t('menu.settings')}</span>
<span className="text-sm mt-1">{t('menu.settings')}</span>
</button>
</div>
</div>

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate, useLocation } from 'react-router-dom';
import Logo from '@/entrypoints/popup/components/Logo';
import { useAuth } from '@/entrypoints/popup/context/AuthContext';
/**
@@ -87,11 +88,15 @@ const Header: React.FC<HeaderProps> = ({
onClick={() => logoClick()}
className="flex items-center hover:opacity-80 transition-opacity"
>
<img src="/assets/images/logo.svg" alt="AliasVault" className="h-8 w-8 mr-2" />
<h1 className="text-gray-900 dark:text-white text-xl font-bold">{t('common.appName')}</h1>
<Logo
width={125}
height={40}
showText={true}
className="text-gray-900 dark:text-white"
/>
{/* Hide beta badge on Safari as it's not allowed to show non-production badges */}
{!import.meta.env.SAFARI && (
<span className="text-primary-500 text-[10px] ml-1 font-normal">BETA</span>
<span className="text-primary-500 text-[10px] font-normal">BETA</span>
)}
</button>
</div>

View File

@@ -27,7 +27,7 @@ const LoginServerInfo: React.FC = () => {
};
return (
<div className="text-xs text-gray-600 dark:text-gray-400 mb-4">
<div className="text-sm text-gray-600 dark:text-gray-400 mb-4">
({t('auth.connectingTo')}{' '}
<button
onClick={handleClick}

View File

@@ -0,0 +1,68 @@
import React from 'react';
interface LogoProps {
className?: string;
width?: number;
height?: number;
showText?: boolean;
color?: string;
}
const Logo: React.FC<LogoProps> = ({
className = '',
width = 200,
height = 50,
showText = true,
color = 'currentColor'
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
xmlSpace="preserve"
version="1.1"
viewBox="0 0 2000 500"
width={width}
height={height}
className={className}
>
{/* Logo mark */}
<path
d="m459.87 294.95c0.016205 5.4005 0.03241 10.801-0.35022 16.873-1.111 6.3392-1.1941 12.173-2.6351 17.649-10.922 41.508-36.731 69.481-77.351 83.408-7.2157 2.4739-14.972 3.3702-22.479 4.995-23.629 0.042205-47.257 0.11453-70.886 0.12027-46.762 0.011322-93.523-0.01416-140.95-0.43411-8.59-2.0024-16.766-2.8352-24.398-5.3326-21.595-7.0666-39.523-19.656-53.708-37.552-10.227-12.903-17.579-27.17-21.28-43.221-1.475-6.3967-2.4711-12.904-3.6852-19.361-0.051849-5.747-0.1037-11.494 0.26915-17.886 4.159-42.973 27.68-71.638 63.562-92.153 0-0.70761-0.001961-1.6988 3.12e-4 -2.69 0.022484-9.8293-1.3071-19.894 0.35664-29.438 3.2391-18.579 11.08-35.272 23.763-49.773 12.098-13.832 26.457-23.989 43.609-30.029 7.813-2.7512 16.14-4.0417 24.234-5.9948 7.392-0.025734 14.784-0.05146 22.835 0.32253 4.1959 0.95392 7.7946 1.2538 11.258 2.1053 17.16 4.2192 32.287 12.176 45.469 24.104 2.2558 2.0411 4.372 6.6241 9.621 3.868 16.839-8.8419 34.718-11.597 53.603-8.594 16.791 2.6699 31.602 9.4308 44.236 20.636 11.531 10.227 19.84 22.841 25.393 37.236 6.3436 16.445 10.389 33.163 6.0798 49.389 7.9587 8.9321 15.807 16.704 22.421 25.414 9.162 12.065 15.33 25.746 18.144 40.776 0.97046 5.1848 1.9111 10.375 2.8654 15.563m-71.597 71.012c5.5615-5.2284 12.002-9.7986 16.508-15.817 10.474-13.992 14.333-29.916 11.288-47.446-2.2496-12.95-8.1973-24.076-17.243-33.063-12.746-12.663-28.865-18.614-46.786-18.569-69.912 0.17712-139.82 0.56831-209.74 0.96176-15.922 0.089599-29.168 7.4209-39.685 18.296-14.45 14.944-20.408 33.343-16.655 54.368 2.2763 12.754 8.2167 23.748 17.158 32.66 13.299 13.255 30.097 18.653 48.728 18.651 59.321-0.005188 118.64 0.042358 177.96-0.046601 9.5912-0.014374 19.181-0.86588 28.773-0.88855 10.649-0.025146 19.978-3.825 29.687-9.1074z"
fill="#EEC170"
/>
<path
d="m162.77 293c15.654 4.3883 20.627 22.967 10.304 34.98-5.3104 6.1795-14.817 8.3208-24.278 5.0472-7.0723-2.4471-12.332-10.362-12.876-17.933-1.0451-14.542 11.089-23.176 21.705-23.046 1.5794 0.019287 3.1517 0.61566 5.1461 0.95184z"
fill="#EEC170"
/>
<path
d="m227.18 293.64c7.8499 2.3973 11.938 8.2143 13.524 15.077 1.8591 8.0439-0.44817 15.706-7.1588 21.121-6.7633 5.4572-14.417 6.8794-22.578 3.1483-8.2972-3.7933-12.836-10.849-12.736-19.438 0.1687-14.497 14.13-25.368 28.948-19.908z"
fill="#EEC170"
/>
<path
d="m261.57 319.07c-2.495-14.418 4.6853-22.603 14.596-26.108 9.8945-3.4995 23.181 3.4303 26.267 13.779 4.6504 15.591-7.1651 29.064-21.665 28.161-8.5254-0.53088-17.202-6.5094-19.198-15.831z"
fill="#EEC170"
/>
<path
d="m336.91 333.41c-9.0175-4.2491-15.337-14.349-13.829-21.682 3.0825-14.989 13.341-20.304 23.018-19.585 10.653 0.79141 17.93 7.407 19.765 17.547 1.9588 10.824-4.1171 19.939-13.494 23.703-5.272 2.1162-10.091 1.5086-15.46 0.017883z"
fill="#EEC170"
/>
{/* Wordmark - only show if showText is true */}
{showText && (
<text
x="550"
y="355"
fontFamily="Arial, Helvetica, sans-serif"
fontWeight="700"
fontSize="290"
letterSpacing="-7"
fill={color}
>
AliasVault
</text>
)}
</svg>
);
};
export default Logo;

View File

@@ -114,7 +114,7 @@ const PasswordField: React.FC<IPasswordFieldProps> = ({
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
className="outline-0 shadow-sm border border-gray-300 bg-gray-50 text-gray-900 sm:text-sm rounded-l-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
className="outline-0 text-sm shadow-sm border border-gray-300 bg-gray-50 text-gray-900 sm:text-sm rounded-l-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
/>
</div>
<div className="flex">

View File

@@ -49,7 +49,7 @@ const UsernameField: React.FC<IUsernameFieldProps> = ({
value={value}
onChange={handleInputChange}
placeholder={placeholder}
className="outline-0 shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-l-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
className="outline-0 text-sm shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-l-lg block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
/>
</div>
<div className="flex">

View File

@@ -51,9 +51,13 @@ export const NavigationProvider: React.FC<{ children: React.ReactNode }> = ({ ch
const segments = location.pathname.split('/').filter(Boolean);
const historyEntries: NavigationHistoryEntry[] = [];
// Build history entries for each segment
let currentPath = '';
for (const segment of segments) {
currentPath += '/' + segment;
for (let i = 0; i < segments.length; i++) {
currentPath += '/' + segments[i];
// For settings subpages, include both /settings and the subpage
// For email details, include both /emails and the specific email
historyEntries.push({
pathname: currentPath,
search: location.search,

View File

@@ -51,21 +51,16 @@ const Reinitialize: React.FC = () => {
if (lastPage && lastVisitTime) {
const timeSinceLastVisit = Date.now() - lastVisitTime;
if (timeSinceLastVisit <= PAGE_MEMORY_DURATION) {
// Restore the navigation history
if (savedHistory?.length) {
// First navigate to credentials page as the base
navigate('/credentials', { replace: true });
// Then restore the history stack
for (const entry of savedHistory) {
navigate(entry.pathname + entry.search + entry.hash);
}
return;
// For nested routes, build up the navigation history properly
if (savedHistory?.length > 1) {
// Navigate to the base route first
navigate(savedHistory[0].pathname, { replace: true });
// Then navigate to the final destination
navigate(lastPage, { replace: false });
} else {
// Simple navigation for non-nested routes
navigate(lastPage, { replace: true });
}
// Fallback to simple navigation if no history
navigate('/credentials', { replace: true });
navigate(lastPage, { replace: true });
return;
}
}

View File

@@ -176,13 +176,13 @@ const AuthSettings: React.FC = () => {
{/* Language Settings Section */}
<div className="mb-6">
<div className="flex flex-col gap-2">
<p className="text-sm font-medium text-gray-900 dark:text-white">{t('common.language')}</p>
<p className="font-medium text-gray-900 dark:text-white">{t('common.language')}</p>
<LanguageSwitcher variant="dropdown" size="sm" />
</div>
</div>
<div className="mb-6">
<label htmlFor="api-connection" className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-2">
<label htmlFor="api-connection" className="block font-medium text-gray-700 dark:text-gray-200 mb-2">
{t('settings.serverUrl')}
</label>
<select
@@ -201,7 +201,7 @@ const AuthSettings: React.FC = () => {
{selectedOption === 'custom' && (
<>
<div className="mb-6">
<label htmlFor="custom-client-url" className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-2">
<label htmlFor="custom-client-url" className="block font-medium text-gray-700 dark:text-gray-200 mb-2">
Custom client URL
</label>
<input
@@ -217,7 +217,7 @@ const AuthSettings: React.FC = () => {
)}
</div>
<div className="mb-6">
<label htmlFor="custom-api-url" className="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-2">
<label htmlFor="custom-api-url" className="block font-medium text-gray-700 dark:text-gray-200 mb-2">
Custom API URL
</label>
<input
@@ -238,7 +238,7 @@ const AuthSettings: React.FC = () => {
{/* Autofill Popup Settings Section */}
<div className="mb-6">
<div className="flex flex-col gap-2">
<p className="text-sm font-medium text-gray-900 dark:text-white">{t('settings.autofillEnabled')}</p>
<p className="font-medium text-gray-900 dark:text-white">{t('settings.autofillEnabled')}</p>
<button
onClick={toggleGlobalPopup}
className={`px-4 py-2 rounded-md transition-colors ${

View File

@@ -361,11 +361,11 @@ const Login: React.FC = () => {
<h2 className="text-xl font-bold dark:text-gray-200">{t('auth.loginTitle')}</h2>
<LoginServerInfo />
<div className="mb-4">
<label className="block text-gray-700 dark:text-gray-200 text-sm font-bold mb-2" htmlFor="username">
<label className="block text-gray-700 dark:text-gray-200 font-bold mb-2" htmlFor="username">
{t('auth.username')}
</label>
<input
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-200 dark:bg-gray-800 dark:border-gray-600 leading-tight focus:outline-none focus:shadow-outline"
className="shadow text-sm appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-200 dark:bg-gray-800 dark:border-gray-600 leading-tight focus:outline-none focus:shadow-outline"
id="username"
type="text"
name="username"
@@ -376,11 +376,11 @@ const Login: React.FC = () => {
/>
</div>
<div className="mb-4">
<label className="block text-gray-700 dark:text-gray-200 text-sm font-bold mb-2" htmlFor="password">
<label className="block text-gray-700 dark:text-gray-200 font-bold mb-2" htmlFor="password">
{t('auth.password')}
</label>
<input
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-200 dark:bg-gray-800 dark:border-gray-600 mb-3 leading-tight focus:outline-none focus:shadow-outline"
className="shadow text-sm appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-200 dark:bg-gray-800 dark:border-gray-600 mb-3 leading-tight focus:outline-none focus:shadow-outline"
id="password"
type="password"
name="password"
@@ -407,7 +407,7 @@ const Login: React.FC = () => {
</Button>
</div>
</form>
<div className="text-center text-sm text-gray-600 dark:text-gray-400">
<div className="text-center text-gray-600 dark:text-gray-400">
{t('auth.noAccount')}{' '}
<a
href={clientUrl ?? ''}

View File

@@ -144,10 +144,10 @@ const Unlock: React.FC = () => {
</div>
</div>
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">
<p className="font-medium text-gray-900 dark:text-white">
{authContext.username}
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
<p className="text-sm text-gray-500 dark:text-gray-400">
{t('auth.loggedIn')}
</p>
</div>
@@ -159,13 +159,13 @@ const Unlock: React.FC = () => {
</h2>
{error && (
<div className="mb-4 text-red-500 dark:text-red-400 text-sm">
<div className="mb-4 text-red-500 dark:text-red-400">
{error}
</div>
)}
<div className="mb-2">
<label className="block text-gray-700 dark:text-gray-200 text-sm font-bold mb-2" htmlFor="password">
<label className="block text-gray-700 dark:text-gray-200 font-bold mb-2" htmlFor="password">
{t('auth.masterPassword')}
</label>
<input
@@ -184,7 +184,7 @@ const Unlock: React.FC = () => {
{t('auth.unlockVault')}
</Button>
<div className="text-sm font-medium text-gray-500 dark:text-gray-200 mt-6">
<div className="font-medium text-gray-500 dark:text-gray-200 mt-6">
{t('auth.switchAccounts')} <button onClick={handleLogout} className="text-primary-700 hover:underline dark:text-primary-500">{t('auth.logout')}</button>
</div>
</form>

View File

@@ -253,7 +253,7 @@ const Upgrade: React.FC = () => {
<form className="w-full px-2 pt-2 pb-2 mb-4">
{error && (
<div className="mb-4 text-red-500 dark:text-red-400 text-sm">
<div className="mb-4 text-red-500 dark:text-red-400">
{error}
</div>
)}
@@ -268,7 +268,7 @@ const Upgrade: React.FC = () => {
</div>
</div>
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">
<p className="font-medium text-gray-900 dark:text-white">
{username}
</p>
</div>
@@ -277,12 +277,12 @@ const Upgrade: React.FC = () => {
<h2 className="text-xl font-bold dark:text-gray-200 mb-4">{t('upgrade.title')}</h2>
<div className="mb-6">
<p className="text-gray-700 dark:text-gray-200 text-sm mb-4">
<p className="text-gray-700 dark:text-gray-200 mb-4">
{t('upgrade.subtitle')}
</p>
<div className="bg-gray-50 dark:bg-gray-800 rounded p-4 mb-4">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium text-gray-700 dark:text-gray-200">{t('upgrade.versionInformation')}</span>
<span className="font-medium text-gray-700 dark:text-gray-200">{t('upgrade.versionInformation')}</span>
<button
type="button"
onClick={showVersionDialog}

View File

@@ -536,8 +536,8 @@ const CredentialAddEdit: React.FC = () => {
<button
type="button"
onClick={() => setMode('random')}
className={`flex-1 py-2 px-4 rounded flex items-center justify-center gap-2 ${
mode === 'random' ? 'bg-primary-500 text-white' : 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
className={`flex-1 py-2 text-sm px-4 rounded flex items-center justify-center gap-2 ${
mode === 'random' ? 'bg-primary-500 text-white font-medium' : 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
}`}
>
<svg className='w-5 h-5' viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
@@ -553,8 +553,8 @@ const CredentialAddEdit: React.FC = () => {
<button
type="button"
onClick={() => setMode('manual')}
className={`flex-1 py-2 px-4 rounded flex items-center justify-center gap-2 ${
mode === 'manual' ? 'bg-primary-500 text-white' : 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
className={`flex-1 py-2 text-sm px-4 rounded flex items-center justify-center gap-2 ${
mode === 'manual' ? 'bg-primary-500 text-white font-medium' : 'bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300'
}`}
>
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
@@ -630,7 +630,7 @@ const CredentialAddEdit: React.FC = () => {
<button
type="button"
onClick={handleGenerateRandomAlias}
className="w-full bg-primary-500 text-white py-2 px-4 rounded hover:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 flex items-center justify-center gap-2"
className="w-full text-sm bg-primary-500 text-white py-2 px-4 rounded hover:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 flex items-center justify-center gap-2"
>
<svg className='w-5 h-5 inline-block' viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>

View File

@@ -188,10 +188,10 @@ const CredentialsList: React.FC = () => {
{credentials.length === 0 ? (
<div className="text-gray-500 dark:text-gray-400 space-y-2 mb-10">
<p className="text-sm">
<p>
{t('credentials.welcomeTitle')}
</p>
<p className="text-sm">
<p>
{t('credentials.welcomeDescription')}
</p>
</div>

View File

@@ -177,14 +177,14 @@ const EmailsList: React.FC = () => {
className="block p-4 bg-white dark:bg-gray-800 rounded-lg shadow hover:shadow-md transition-shadow border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700"
>
<div className="flex justify-between items-start mb-2">
<div className="text-sm text-gray-900 dark:text-white mb-1 font-bold">
<div className="text-gray-900 dark:text-white mb-1 font-bold">
{email.subject}
</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
{formatEmailDate(email.dateSystem)}
</div>
</div>
<div className="text-sm text-gray-600 dark:text-gray-300 line-clamp-2">
<div className="text-gray-600 text-sm dark:text-gray-300 line-clamp-2">
{email.messagePreview}
</div>
</Link>

View File

@@ -48,14 +48,14 @@ const AutoLockSettings: React.FC = () => {
<div className="p-4">
<div>
<div className="flex items-center mb-2">
<p className="text-sm font-medium text-gray-900 dark:text-white">{t('settings.autoLockTimeout')}</p>
<p className="font-medium text-gray-900 dark:text-white">{t('settings.autoLockTimeout')}</p>
<HelpModal
titleKey="settings.autoLockTimeout"
contentKey="settings.autoLockTimeoutHelp"
className="ml-2"
/>
</div>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-3">{t('settings.autoLockTimeoutDescription')}</p>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-3">{t('settings.autoLockTimeoutDescription')}</p>
<select
value={autoLockTimeout}
onChange={(e) => setAutoLockTimeoutSetting(Number(e.target.value))}

View File

@@ -167,8 +167,8 @@ const AutofillSettings: React.FC = () => {
<div className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">{t('settings.autofillPopup')}</p>
<p className={`text-xs mt-1 ${settings.isGloballyEnabled ? 'text-gray-600 dark:text-gray-400' : 'text-red-600 dark:text-red-400'}`}>
<p className="font-medium text-gray-900 dark:text-white">{t('settings.autofillPopup')}</p>
<p className={`text-sm mt-1 ${settings.isGloballyEnabled ? 'text-gray-600 dark:text-gray-400' : 'text-red-600 dark:text-red-400'}`}>
{settings.isGloballyEnabled ? t('settings.activeOnAllSites') : t('settings.disabledOnAllSites')}
</p>
</div>
@@ -195,12 +195,12 @@ const AutofillSettings: React.FC = () => {
<div className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">{t('settings.autofillPopupOn')}{settings.currentUrl}</p>
<p className={`text-xs mt-1 ${settings.isEnabled ? 'text-gray-600 dark:text-gray-400' : 'text-red-600 dark:text-red-400'}`}>
<p className="font-medium text-gray-900 dark:text-white">{t('settings.autofillPopupOn')}{settings.currentUrl}</p>
<p className={`text-sm mt-1 ${settings.isEnabled ? 'text-gray-600 dark:text-gray-400' : 'text-red-600 dark:text-red-400'}`}>
{settings.isEnabled ? t('settings.enabledForThisSite') : t('settings.disabledForThisSite')}
</p>
{!settings.isEnabled && settings.temporaryDisabledUrls[settings.currentUrl] && (
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
<p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
{t('settings.temporarilyDisabledUntil')}{new Date(settings.temporaryDisabledUrls[settings.currentUrl]).toLocaleTimeString()}
</p>
)}
@@ -238,8 +238,8 @@ const AutofillSettings: React.FC = () => {
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<div className="p-4">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white mb-2">{t('settings.autofillMatchingMode')}</p>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-3">{t('settings.autofillMatchingModeDescription')}</p>
<p className="font-medium text-gray-900 dark:text-white mb-2">{t('settings.autofillMatchingMode')}</p>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-3">{t('settings.autofillMatchingModeDescription')}</p>
<select
value={autofillMatchingMode}
onChange={(e) => setAutofillMatchingModeSetting(e.target.value as AutofillMatchingMode)}

View File

@@ -46,8 +46,8 @@ const ClipboardSettings: React.FC = () => {
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<div className="p-4">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white mb-2">{t('settings.clipboardClearTimeout')}</p>
<p className="text-xs text-gray-600 dark:text-gray-400 mb-3">{t('settings.clipboardClearTimeoutDescription')}</p>
<p className="font-medium text-gray-900 dark:text-white mb-2">{t('settings.clipboardClearTimeout')}</p>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-3">{t('settings.clipboardClearTimeoutDescription')}</p>
<select
value={clipboardTimeout}
onChange={(e) => setClipboardClearTimeout(Number(e.target.value))}

View File

@@ -49,11 +49,11 @@ const ContextMenuSettings: React.FC = () => {
<div className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">{t('settings.rightClickContextMenu')}</p>
<p className={`text-xs mt-1 ${isContextMenuEnabled ? 'text-gray-600 dark:text-gray-400' : 'text-red-600 dark:text-red-400'}`}>
<p className="font-medium text-gray-900 dark:text-white">{t('settings.rightClickContextMenu')}</p>
<p className={`text-sm mt-1 ${isContextMenuEnabled ? 'text-gray-600 dark:text-gray-400' : 'text-red-600 dark:text-red-400'}`}>
{isContextMenuEnabled ? t('settings.contextMenuEnabled') : t('settings.contextMenuDisabled')}
</p>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
{t('settings.contextMenuDescription')}
</p>
</div>

View File

@@ -1,13 +1,20 @@
import React from 'react';
import React, { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import LanguageSwitcher from '@/entrypoints/popup/components/LanguageSwitcher';
import { useLoading } from '@/entrypoints/popup/context/LoadingContext';
/**
* Language settings page component.
*/
const LanguageSettings: React.FC = () => {
const { t } = useTranslation();
const { setIsInitialLoading } = useLoading();
useEffect(() => {
// Mark initial loading as complete
setIsInitialLoading(false);
}, [setIsInitialLoading]);
return (
<div className="space-y-6">
@@ -16,7 +23,7 @@ const LanguageSettings: React.FC = () => {
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<div className="p-4">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white mb-3">{t('settings.selectLanguage')}</p>
<p className="font-medium text-gray-900 dark:text-white mb-3">{t('settings.selectLanguage')}</p>
<LanguageSwitcher variant="dropdown" size="sm" />
</div>
</div>

View File

@@ -167,10 +167,10 @@ const Settings: React.FC = () => {
</div>
</div>
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">
<p className="text font-medium text-gray-900 dark:text-white">
{authContext.username}
</p>
<p className="text-xs text-gray-500 dark:text-gray-400">
<p className="text-sm text-gray-500 dark:text-gray-400">
{t('settings.loggedIn')}
</p>
</div>
@@ -224,7 +224,7 @@ const Settings: React.FC = () => {
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
/>
</svg>
<span className="text-sm text-gray-900 dark:text-white">{t('settings.autofillSettings')}</span>
<span className="text-gray-900 dark:text-white">{t('settings.autofillSettings')}</span>
</div>
<svg
className="w-4 h-4 text-gray-400"
@@ -256,7 +256,7 @@ const Settings: React.FC = () => {
d="M4 6h16M4 12h16m-7 6h7"
/>
</svg>
<span className="text-sm text-gray-900 dark:text-white">{t('settings.contextMenuSettings')}</span>
<span className="text-gray-900 dark:text-white">{t('settings.contextMenuSettings')}</span>
</div>
<svg
className="w-4 h-4 text-gray-400"
@@ -288,7 +288,7 @@ const Settings: React.FC = () => {
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
/>
</svg>
<span className="text-sm text-gray-900 dark:text-white">{t('settings.autoLockTimeout')}</span>
<span className="text-gray-900 dark:text-white">{t('settings.autoLockTimeout')}</span>
</div>
<svg
className="w-4 h-4 text-gray-400"
@@ -320,7 +320,7 @@ const Settings: React.FC = () => {
d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2"
/>
</svg>
<span className="text-sm text-gray-900 dark:text-white">{t('settings.clipboardSettings')}</span>
<span className="text-gray-900 dark:text-white">{t('settings.clipboardSettings')}</span>
</div>
<svg
className="w-4 h-4 text-gray-400"
@@ -352,7 +352,7 @@ const Settings: React.FC = () => {
d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129"
/>
</svg>
<span className="text-sm text-gray-900 dark:text-white">{t('settings.language')}</span>
<span className="text-gray-900 dark:text-white">{t('settings.language')}</span>
</div>
<svg
className="w-4 h-4 text-gray-400"
@@ -374,7 +374,7 @@ const Settings: React.FC = () => {
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<div className="p-4">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white mb-2">{t('settings.theme')}</p>
<p className="font-medium text-gray-900 dark:text-white mb-2">{t('settings.theme')}</p>
<div className="flex flex-col space-y-2">
<label className="flex items-center">
<input
@@ -385,7 +385,7 @@ const Settings: React.FC = () => {
onChange={() => setThemePreference('system')}
className="mr-2"
/>
<span className="text-xs text-gray-700 dark:text-gray-300">{t('settings.useDefault')}</span>
<span className="text-sm text-gray-700 dark:text-gray-300">{t('settings.useDefault')}</span>
</label>
<label className="flex items-center">
<input
@@ -396,7 +396,7 @@ const Settings: React.FC = () => {
onChange={() => setThemePreference('light')}
className="mr-2"
/>
<span className="text-xs text-gray-700 dark:text-gray-300">{t('settings.light')}</span>
<span className="text-sm text-gray-700 dark:text-gray-300">{t('settings.light')}</span>
</label>
<label className="flex items-center">
<input
@@ -407,7 +407,7 @@ const Settings: React.FC = () => {
onChange={() => setThemePreference('dark')}
className="mr-2"
/>
<span className="text-xs text-gray-700 dark:text-gray-300">{t('settings.dark')}</span>
<span className="text-sm text-gray-700 dark:text-gray-300">{t('settings.dark')}</span>
</label>
</div>
</div>
@@ -423,7 +423,7 @@ const Settings: React.FC = () => {
<div className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-gray-900 dark:text-white">{t('settings.configureKeyboardShortcuts')}</p>
<p className="font-medium text-gray-900 dark:text-white">{t('settings.configureKeyboardShortcuts')}</p>
</div>
<button
onClick={openKeyboardShortcuts}

View File

@@ -1,3 +1,7 @@
body {
font-size: 75%;
html {
font-size: 14px;
}
body {
font-size: 100%;
}