mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 13:00:39 +00:00
feat: update mobile layout query to 1180px and enhance icon loading experience
This commit is contained in:
+1
-1
@@ -217,7 +217,7 @@ export default function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
|
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;
|
||||||
const media = window.matchMedia('(max-width: 900px)');
|
const media = window.matchMedia('(max-width: 1180px)');
|
||||||
const sync = () => setMobileLayout(media.matches);
|
const sync = () => setMobileLayout(media.matches);
|
||||||
sync();
|
sync();
|
||||||
if (typeof media.addEventListener === 'function') {
|
if (typeof media.addEventListener === 'function') {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ interface SendsPageProps {
|
|||||||
|
|
||||||
type SendTypeFilter = 'all' | 'text' | 'file';
|
type SendTypeFilter = 'all' | 'text' | 'file';
|
||||||
const AUTO_COPY_KEY = 'nodewarden.send.auto_copy_link.v1';
|
const AUTO_COPY_KEY = 'nodewarden.send.auto_copy_link.v1';
|
||||||
const MOBILE_LAYOUT_QUERY = '(max-width: 900px)';
|
const MOBILE_LAYOUT_QUERY = '(max-width: 1180px)';
|
||||||
|
|
||||||
function daysFromNow(iso: string | null | undefined, fallback: number): string {
|
function daysFromNow(iso: string | null | undefined, fallback: number): string {
|
||||||
if (!iso) return String(fallback);
|
if (!iso) return String(fallback);
|
||||||
|
|||||||
@@ -73,23 +73,31 @@ function TotpListIcon({ cipher }: { cipher: Cipher }) {
|
|||||||
const uri = firstCipherUri(cipher);
|
const uri = firstCipherUri(cipher);
|
||||||
const host = hostFromUri(uri);
|
const host = hostFromUri(uri);
|
||||||
const [errored, setErrored] = useState(() => (host ? failedIconHosts.has(host) : false));
|
const [errored, setErrored] = useState(() => (host ? failedIconHosts.has(host) : false));
|
||||||
|
const [loaded, setLoaded] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setErrored(host ? failedIconHosts.has(host) : false);
|
setErrored(host ? failedIconHosts.has(host) : false);
|
||||||
|
setLoaded(false);
|
||||||
}, [host]);
|
}, [host]);
|
||||||
|
|
||||||
if (host && !errored) {
|
if (host && !errored) {
|
||||||
return (
|
return (
|
||||||
<img
|
<span className="list-icon-stack">
|
||||||
className="list-icon"
|
<span className={`list-icon-fallback ${loaded ? 'hidden' : ''}`}>
|
||||||
src={websiteIconUrl(host)}
|
<Globe size={18} />
|
||||||
alt=""
|
</span>
|
||||||
loading="lazy"
|
<img
|
||||||
referrerPolicy="no-referrer"
|
className={`list-icon ${loaded ? 'loaded' : ''}`}
|
||||||
onError={() => {
|
src={websiteIconUrl(host)}
|
||||||
failedIconHosts.add(host);
|
alt=""
|
||||||
setErrored(true);
|
loading="lazy"
|
||||||
}}
|
referrerPolicy="no-referrer"
|
||||||
/>
|
onLoad={() => setLoaded(true)}
|
||||||
|
onError={() => {
|
||||||
|
failedIconHosts.add(host);
|
||||||
|
setErrored(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export const CREATE_TYPE_OPTIONS: TypeOption[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const VAULT_SORT_STORAGE_KEY = 'nodewarden.vault.sort.v1';
|
export const VAULT_SORT_STORAGE_KEY = 'nodewarden.vault.sort.v1';
|
||||||
export const MOBILE_LAYOUT_QUERY = '(max-width: 900px)';
|
export const MOBILE_LAYOUT_QUERY = '(max-width: 1180px)';
|
||||||
export const VAULT_LIST_ROW_HEIGHT = 74;
|
export const VAULT_LIST_ROW_HEIGHT = 74;
|
||||||
export const VAULT_LIST_OVERSCAN = 10;
|
export const VAULT_LIST_OVERSCAN = 10;
|
||||||
export const VAULT_SORT_OPTIONS: Array<{ value: VaultSortMode; label: string }> = [
|
export const VAULT_SORT_OPTIONS: Array<{ value: VaultSortMode; label: string }> = [
|
||||||
@@ -433,23 +433,31 @@ export function VaultListIcon({ cipher }: { cipher: Cipher }) {
|
|||||||
const uri = firstCipherUri(cipher);
|
const uri = firstCipherUri(cipher);
|
||||||
const host = hostFromUri(uri);
|
const host = hostFromUri(uri);
|
||||||
const [errored, setErrored] = useState(() => (host ? failedIconHosts.has(host) : false));
|
const [errored, setErrored] = useState(() => (host ? failedIconHosts.has(host) : false));
|
||||||
|
const [loaded, setLoaded] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setErrored(host ? failedIconHosts.has(host) : false);
|
setErrored(host ? failedIconHosts.has(host) : false);
|
||||||
|
setLoaded(false);
|
||||||
}, [host]);
|
}, [host]);
|
||||||
|
|
||||||
if (host && !errored) {
|
if (host && !errored) {
|
||||||
return (
|
return (
|
||||||
<img
|
<span className="list-icon-stack">
|
||||||
className="list-icon"
|
<span className={`list-icon-fallback ${loaded ? 'hidden' : ''}`}>
|
||||||
src={websiteIconUrl(host)}
|
<TypeIcon type={Number(cipher.type || 1)} />
|
||||||
alt=""
|
</span>
|
||||||
loading="lazy"
|
<img
|
||||||
referrerPolicy="no-referrer"
|
className={`list-icon ${loaded ? 'loaded' : ''}`}
|
||||||
onError={() => {
|
src={websiteIconUrl(host)}
|
||||||
failedIconHosts.add(host);
|
alt=""
|
||||||
setErrored(true);
|
loading="lazy"
|
||||||
}}
|
referrerPolicy="no-referrer"
|
||||||
/>
|
onLoad={() => setLoaded(true)}
|
||||||
|
onError={() => {
|
||||||
|
failedIconHosts.add(host);
|
||||||
|
setErrored(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 1180px) {
|
||||||
.auth-page {
|
.auth-page {
|
||||||
@apply items-start p-3.5;
|
@apply items-start p-3.5;
|
||||||
}
|
}
|
||||||
@@ -114,6 +114,10 @@
|
|||||||
@apply h-[34px] w-[34px];
|
@apply h-[34px] w-[34px];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.brand-wordmark {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.mobile-page-title {
|
.mobile-page-title {
|
||||||
@apply inline;
|
@apply inline;
|
||||||
}
|
}
|
||||||
@@ -410,7 +414,7 @@
|
|||||||
.detail-actions {
|
.detail-actions {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
gap: 10px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-actions .actions {
|
.detail-actions .actions {
|
||||||
@@ -624,7 +628,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 1180px) {
|
||||||
.backup-grid {
|
.backup-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
--dur-fast: 180ms;
|
--dur-fast: 180ms;
|
||||||
--dur-medium: 240ms;
|
--dur-medium: 240ms;
|
||||||
--dur-panel: 280ms;
|
--dur-panel: 280ms;
|
||||||
--actions-gap: clamp(0px, calc((100vw - 520px) * 1), 10px);
|
--actions-gap: clamp(5px, calc((100vw - 520px) * 1), 10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-theme='dark'] {
|
:root[data-theme='dark'] {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.vault-grid {
|
.vault-grid {
|
||||||
@apply grid h-full min-h-0 gap-3 p-0.5;
|
@apply grid h-full min-h-0 gap-3 p-0.5;
|
||||||
grid-template-columns: 240px minmax(420px, 46%) minmax(575px, 1fr);
|
grid-template-columns: 270px minmax(400px, 36%) minmax(400px, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar,
|
.sidebar,
|
||||||
@@ -355,12 +355,38 @@
|
|||||||
|
|
||||||
.list-icon {
|
.list-icon {
|
||||||
@apply h-6 w-6 rounded-md;
|
@apply h-6 w-6 rounded-md;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity var(--dur-fast) var(--ease-smooth);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-icon-stack {
|
||||||
|
@apply grid h-6 w-6 place-items-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-icon-stack > .list-icon,
|
||||||
|
.list-icon-stack > .list-icon-fallback {
|
||||||
|
grid-area: 1 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-icon-stack > .list-icon {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-icon-stack > .list-icon.loaded {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-icon-fallback.hidden {
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-icon-fallback {
|
.list-icon-fallback {
|
||||||
@apply grid place-items-center;
|
@apply grid place-items-center;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
transition: color var(--dur-fast) var(--ease-smooth), transform 240ms var(--ease-out-soft);
|
transition:
|
||||||
|
color var(--dur-fast) var(--ease-smooth),
|
||||||
|
opacity var(--dur-fast) var(--ease-smooth),
|
||||||
|
transform 240ms var(--ease-out-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-icon-fallback svg {
|
.list-icon-fallback svg {
|
||||||
@@ -615,7 +641,7 @@
|
|||||||
|
|
||||||
.totp-codes-list {
|
.totp-codes-list {
|
||||||
@apply grid w-full items-start gap-2.5;
|
@apply grid w-full items-start gap-2.5;
|
||||||
grid-template-columns: repeat(var(--totp-columns, 1), minmax(320px, 1fr));
|
grid-template-columns: repeat(var(--totp-columns, 1), minmax(300px, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.totp-code-row {
|
.totp-code-row {
|
||||||
|
|||||||
Reference in New Issue
Block a user