Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/brand/dewee-mascot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions public/fonts/NOTICE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Fonts bundled with the Dewee extension, the same families dewee.sh uses.
Each is licensed under the SIL Open Font License, Version 1.1 (https://openfontlicense.org).

Be Vietnam Pro Copyright 2021 The Be Vietnam Pro Project Authors (https://github.com/bettergui/BeVietnamPro)
Newsreader Copyright 2020 The Newsreader Project Authors (https://github.com/productiontype/Newsreader)
JetBrains Mono Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)

The files are the Vietnamese, Latin Extended and Latin subsets served by Google Fonts.
Binary file added public/fonts/be-vietnam-pro-400-latin-ext.woff2
Binary file not shown.
Binary file added public/fonts/be-vietnam-pro-400-latin.woff2
Binary file not shown.
Binary file added public/fonts/be-vietnam-pro-400-vietnamese.woff2
Binary file not shown.
Binary file added public/fonts/be-vietnam-pro-500-latin-ext.woff2
Binary file not shown.
Binary file added public/fonts/be-vietnam-pro-500-latin.woff2
Binary file not shown.
Binary file added public/fonts/be-vietnam-pro-500-vietnamese.woff2
Binary file not shown.
Binary file added public/fonts/be-vietnam-pro-600-latin-ext.woff2
Binary file not shown.
Binary file added public/fonts/be-vietnam-pro-600-latin.woff2
Binary file not shown.
Binary file not shown.
Binary file added public/fonts/jetbrains-mono-400-latin.woff2
Binary file not shown.
Binary file added public/fonts/jetbrains-mono-400-vietnamese.woff2
Binary file not shown.
Binary file added public/fonts/newsreader-latin-ext.woff2
Binary file not shown.
Binary file added public/fonts/newsreader-latin.woff2
Binary file not shown.
Binary file added public/fonts/newsreader-vietnamese.woff2
Binary file not shown.
Binary file modified public/icons/128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/icons/16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/icons/32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/icons/48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/patterns/dong-son-drum-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/patterns/dong-son-drum-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/patterns/dong-son-tile-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/patterns/dong-son-tile-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions src/credentials/ActionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { useState } from 'react';
import { isUiActionOpen, type UiActionCard, type UiActionPayloadByKind } from '@/protocol/ui-action';
import { errorText, useI18n } from '@/shared/i18n';
import { IconExternal } from '@/shared/icons';
import { CredentialsForm } from './CredentialsForm';
import type { RespondFn } from './respond-types';

Expand Down Expand Up @@ -112,7 +113,7 @@ function OAuthCard({ card, respond, deweeUrl }: CardProps & { card: Extract<UiAc
<div className="card-actions">
{deweeUrl ? (
<a className="btn" href={deweeUrl} target="_blank" rel="noopener noreferrer">
{t('oauth.openDewee')}
{t('oauth.openDewee')} <IconExternal size={13} />
</a>
) : null}
<button type="button" className="btn btn-primary" disabled={busy} onClick={() => void submit({})}>
Expand Down Expand Up @@ -184,8 +185,8 @@ function CardBody({ card, respond, deweeUrl }: CardProps) {
<p className="muted small">
{t('card.openInDewee')}{' '}
{deweeUrl ? (
<a href={deweeUrl} target="_blank" rel="noopener noreferrer">
Dewee ↗
<a className="external-link" href={deweeUrl} target="_blank" rel="noopener noreferrer">
Dewee <IconExternal size={12} />
</a>
) : null}
</p>
Expand Down
3 changes: 2 additions & 1 deletion src/credentials/CredentialsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { useId, useState, type FormEvent } from 'react';
import type { SecretRequestEnvelope } from '@/protocol/ui-action';
import { errorText, useI18n } from '@/shared/i18n';
import { IconLock } from '@/shared/icons';
import { fieldLabel, targetLabel } from './labels';
import type { RespondFn } from './respond-types';

Expand Down Expand Up @@ -35,7 +36,7 @@ export function CredentialsForm({ card, respond, interactive }: { card: SecretRe
const head = (
<div className="secret-head">
<p className="secret-destination">
<span aria-hidden="true">🔒</span>{' '}
<IconLock className="secret-icon" size={14} />
{/* A card closed without an answer (cancelled, expired, failed) must not claim it saved anything. */}
{t(interactive || card.status === 'resolved' ? 'secret.destination' : 'secret.destinationClosed', { target: destination })}
</p>
Expand Down
29 changes: 20 additions & 9 deletions src/options/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useState } from 'react';
import { ConnectForm } from '@/shared/ConnectForm';
import { removeProfile, signOutProfile, verifyProfile } from '@/shared/connect';
import { errorText, I18nContext, useI18n } from '@/shared/i18n';
import { BrandMark, IconLock, IconPlus } from '@/shared/icons';
import { localePrefs, themes, type Profile } from '@/shared/settings';
import { useSettings, type SettingsState } from '@/shared/use-settings';
import './options.css';
Expand All @@ -28,11 +29,15 @@ function ProfileRow({ profile, active, connected, update }: { profile: Profile;
return (
<li className="profile-row" data-profile-kind={profile.kind}>
<div className="profile-main">
<strong>{profile.name}</strong>
{active ? <span className="badge">{t('settings.active')}</span> : null}
<span className="muted small block mono">{profile.origin}</span>
<div className="profile-title">
<span className={connected ? 'conn-dot on' : 'conn-dot'} aria-hidden="true" />
<strong className="truncate">{profile.name}</strong>
{active ? <span className="badge">{t('settings.active')}</span> : null}
</div>
<span className="muted small block mono truncate">{profile.origin}</span>
<span className="muted small block">
{profile.kind === 'cloud' ? t('connect.cloud') : t('connect.selfHosted')} · {connected ? status || '✓' : t('settings.notConnected')}
{profile.kind === 'cloud' ? t('connect.cloud') : t('connect.selfHosted')}
{connected ? (status ? ` · ${status}` : '') : ` · ${t('settings.notConnected')}`}
</span>
</div>
<div className="profile-actions">
Expand Down Expand Up @@ -89,12 +94,15 @@ export function Settings() {
return (
<I18nContext.Provider value={{ t, locale }}>
<main className="options">
<h1>{t('settings.title')}</h1>
<header className="options-head">
<BrandMark size={40} />
<h1>{t('settings.title')}</h1>
</header>
<section aria-labelledby="profiles-heading">
<div className="section-head">
<h2 id="profiles-heading">{t('settings.profiles')}</h2>
<button type="button" className="btn" onClick={() => setAdding((v) => !v)} aria-expanded={adding}>
+ {t('settings.addProfile')}
<button type="button" className="btn small" onClick={() => setAdding((v) => !v)} aria-expanded={adding}>
<IconPlus size={14} /> {t('settings.addProfile')}
</button>
</div>
{adding ? (
Expand All @@ -110,7 +118,7 @@ export function Settings() {
</section>
<section aria-labelledby="prefs-heading">
<h2 id="prefs-heading">{t('settings.preferences')}</h2>
<div className="prefs">
<div className="prefs panel">
<label className="field">
<span>{t('settings.theme')}</span>
<select className="input" value={settings?.prefs.theme ?? 'system'} onChange={(e) => {
Expand Down Expand Up @@ -139,7 +147,10 @@ export function Settings() {
</select>
</label>
</div>
<p className="muted small">{t('settings.privacy')}</p>
<p className="privacy muted small">
<IconLock size={13} />
{t('settings.privacy')}
</p>
</section>
</main>
</I18nContext.Provider>
Expand Down
131 changes: 113 additions & 18 deletions src/options/options.css
Original file line number Diff line number Diff line change
@@ -1,54 +1,149 @@
@import '../shared/components.css';

/* The drum relief rises from the top-right corner of the settings page. */
body {
background-image: var(--drum-face);
background-repeat: no-repeat;
background-size: 520px;
background-position: right -260px top -260px;
}

.options {
max-width: 720px;
max-width: 680px;
margin: 0 auto;
padding: 24px 16px 48px;
padding: 40px 20px 64px;
display: grid;
gap: 24px;
gap: 32px;
}
.options-head {
display: flex;
align-items: center;
gap: 12px;
}
.options h1 {
margin: 0;
font-size: 22px;
font-family: var(--font-display-stack);
font-size: 28px;
font-weight: 500;
line-height: 1.15;
letter-spacing: var(--tracking-display);
}
.options h2 {
margin: 0 0 10px;
font-size: 16px;
display: flex;
align-items: center;
gap: var(--space-2);
margin: 0 0 12px;
font: 400 11px/1.4 var(--font-mono-stack);
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--accent-ink);
}
.options h2::before {
content: '';
width: 14px;
height: 1px;
background: currentColor;
}
.options section {
display: grid;
}
.section-head {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.section-head h2 {
margin: 0;
}
.panel {
padding: 14px;
padding: 16px;
margin-bottom: 12px;
border: 1px solid var(--hairline);
border-radius: var(--radius);
background: var(--paper-2);
border: 1px solid var(--rule);
border-radius: var(--radius-3);
background: var(--surface);
box-shadow: var(--shadow-1);
}
.profile-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 8px;
border: 1px solid var(--rule);
border-radius: var(--radius-3);
background: var(--surface);
box-shadow: var(--shadow-1);
overflow: hidden;
}
.profile-list:empty {
display: none;
}
.profile-row {
display: grid;
gap: 10px;
padding: 12px;
border: 1px solid var(--hairline);
border-radius: var(--radius);
background: var(--paper-2);
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 12px 16px;
padding: 14px 16px;
}
.profile-row + .profile-row {
border-top: 1px solid var(--rule);
}
.profile-row > .connect-form {
grid-column: 1 / -1;
padding-top: 12px;
border-top: 1px dashed var(--rule);
}
.profile-main {
display: grid;
gap: 2px;
min-width: 0;
}
.profile-title {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.profile-title .badge {
margin-left: 0;
}
.conn-dot {
width: 7px;
height: 7px;
flex: none;
border-radius: 50%;
background: var(--rule-strong);
}
.conn-dot.on {
background: var(--success);
box-shadow: 0 0 0 3px var(--success-soft);
}
.profile-actions {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: 6px;
}
.prefs {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 12px;
gap: 14px;
}
.privacy {
display: flex;
align-items: flex-start;
gap: 8px;
margin: 4px 2px 0;
}
.privacy svg {
flex: none;
margin-top: 3px;
}

@media (max-width: 520px) {
.profile-row {
grid-template-columns: minmax(0, 1fr);
}
.profile-actions {
justify-content: flex-start;
}
}
2 changes: 1 addition & 1 deletion src/shared/ConnectForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function ConnectForm({ reconnect, onDone }: { reconnect?: Profile; onDone
))}
</div>
)}
<p className="muted small">{mode === 'cloud' ? t('connect.cloudHint') : t('connect.selfHostedHint')}</p>
<p className="muted small form-hint">{mode === 'cloud' ? t('connect.cloudHint') : t('connect.selfHostedHint')}</p>

{reconnect ? null : (
<label className="field" htmlFor={`${id}-name`}>
Expand Down
Loading
Loading