Fix CI: remove unused prop, centralize color helpers, extract constants, memoize Sets, move @types/dompurify to devDeps
This commit is contained in:
Generated
+3
-1
@@ -77,7 +77,6 @@
|
||||
"@radix-ui/react-tooltip": "^1.1.4",
|
||||
"@sentry/react": "^10.42.0",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@unhead/addons": "^2.0.10",
|
||||
"@unhead/react": "^2.0.10",
|
||||
"blurhash": "^2.0.5",
|
||||
@@ -125,6 +124,7 @@
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/react": "^18.3.1",
|
||||
@@ -4005,6 +4005,7 @@
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz",
|
||||
"integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/trusted-types": "*"
|
||||
@@ -4123,6 +4124,7 @@
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
|
||||
+1
-1
@@ -85,7 +85,6 @@
|
||||
"@radix-ui/react-tooltip": "^1.1.4",
|
||||
"@sentry/react": "^10.42.0",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@unhead/addons": "^2.0.10",
|
||||
"@unhead/react": "^2.0.10",
|
||||
"blurhash": "^2.0.5",
|
||||
@@ -133,6 +132,7 @@
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/react": "^18.3.1",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useMemo, useState, useEffect, useId } from 'react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
import { hexToHslString, hexToRgb, rgbToHsl, hslToRgb, getLuminance, getContrastRatio, parseHsl, formatHsl } from '@/lib/colorUtils';
|
||||
import { hexToHslString, hexToRgb, rgbToHsl, hslToRgb, getLuminance, getContrastRatio, parseHsl, formatHsl, hexLuminance } from '@/lib/colorUtils';
|
||||
import type { CoreThemeColors } from '@/themes';
|
||||
import type { NostrEvent } from '@nostrify/nostrify';
|
||||
|
||||
@@ -195,10 +195,6 @@ function DiagonalStripesLayout({ colors }: { colors: string[] }) {
|
||||
|
||||
// ─── Palette → theme mapping ─────────────────────────────
|
||||
|
||||
function hexLuminance(hex: string): number {
|
||||
return getLuminance(...hexToRgb(hex));
|
||||
}
|
||||
|
||||
function hexContrast(hex1: string, hex2: string): number {
|
||||
return getContrastRatio(hexToRgb(hex1), hexToRgb(hex2));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* matching the approach used in mew and espy for kind 3367 color moments.
|
||||
*/
|
||||
|
||||
import { hexLuminance } from '@/lib/colorUtils';
|
||||
|
||||
export type PaletteLayout =
|
||||
| 'horizontal'
|
||||
| 'vertical'
|
||||
@@ -169,14 +171,6 @@ function DiagonalStripesLayout({ colors }: { colors: string[] }) {
|
||||
);
|
||||
}
|
||||
|
||||
function hexLum(hex: string): number {
|
||||
const h = hex.replace('#', '');
|
||||
const r = parseInt(h.slice(0, 2), 16) / 255;
|
||||
const g = parseInt(h.slice(2, 4), 16) / 255;
|
||||
const b = parseInt(h.slice(4, 6), 16) / 255;
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
}
|
||||
|
||||
export function ColorPaletteDisplay({
|
||||
colors,
|
||||
layout = 'horizontal',
|
||||
@@ -185,7 +179,7 @@ export function ColorPaletteDisplay({
|
||||
}: ColorPaletteDisplayProps) {
|
||||
if (colors.length === 0) return null;
|
||||
|
||||
const avgLum = colors.reduce((s, c) => s + hexLum(c), 0) / colors.length;
|
||||
const avgLum = colors.reduce((s, c) => s + hexLuminance(c), 0) / colors.length;
|
||||
const emojiColorClass = avgLum > 0.5 ? 'text-black/80' : 'text-white/90';
|
||||
|
||||
return (
|
||||
|
||||
@@ -16,6 +16,8 @@ import { backgroundTextColor } from '@/lib/colorUtils';
|
||||
import {
|
||||
LETTER_KIND,
|
||||
FONT_OPTIONS,
|
||||
LINE_HEIGHT_RATIO,
|
||||
DEFAULT_STATIONERY_COLOR,
|
||||
resolveStationery,
|
||||
type Stationery,
|
||||
type FrameStyle,
|
||||
@@ -36,9 +38,9 @@ import { SendAnimation, useEnvelopeDimensions } from './SendAnimation';
|
||||
/** Lightweight letter preview used inside the send animation */
|
||||
function AnimationLetter({ content, width }: { content: LetterContent; width: number }) {
|
||||
const { text: textColor, line: lineColor } = useStationeryColors(content.stationery);
|
||||
const resolved = resolveStationery(content.stationery ?? { color: '#F5E6D3' });
|
||||
const resolved = resolveStationery(content.stationery ?? { color: DEFAULT_STATIONERY_COLOR });
|
||||
const fontFamily = resolved.fontFamily ?? FONT_OPTIONS[0].family;
|
||||
const lh = Math.round(width * 0.084);
|
||||
const lh = Math.round(width * LINE_HEIGHT_RATIO);
|
||||
|
||||
return (
|
||||
<div className="relative" style={{ containerType: 'inline-size', width }}>
|
||||
@@ -268,8 +270,8 @@ export function ComposeLetterSheet({ onClose, toPubkey }: ComposeLetterSheetProp
|
||||
|| recipientAuthor.data?.metadata?.name
|
||||
|| (resolvedRecipient ? genUserName(resolvedRecipient) : 'friend');
|
||||
|
||||
const resolvedSt = useMemo(() => resolveStationery(stationery ?? { color: '#F5E6D3' }), [stationery]);
|
||||
const bgColor = resolvedSt.color ?? '#F5E6D3';
|
||||
const resolvedSt = useMemo(() => resolveStationery(stationery ?? { color: DEFAULT_STATIONERY_COLOR }), [stationery]);
|
||||
const bgColor = resolvedSt.color ?? DEFAULT_STATIONERY_COLOR;
|
||||
const primaryColor = resolvedSt.primaryColor ?? '#7c52e0';
|
||||
const textColor = resolvedSt.textColor ?? backgroundTextColor(bgColor);
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ import { Clock } from 'lucide-react';
|
||||
import { useAuthor } from '@/hooks/useAuthor';
|
||||
import { useDecryptLetter } from '@/hooks/useLetters';
|
||||
import { genUserName } from '@/lib/genUserName';
|
||||
import { resolveStationery, type Letter } from '@/lib/letterTypes';
|
||||
import { hexToRgb, rgbToHex, hexLuminance } from '@/lib/colorUtils';
|
||||
import { resolveStationery, DEFAULT_STATIONERY_COLOR, type Letter } from '@/lib/letterTypes';
|
||||
import { hexLuminance, darkenHex, lightenHex, blendHex } from '@/lib/colorUtils';
|
||||
import { StationeryBackground } from './StationeryBackground';
|
||||
|
||||
interface EnvelopeCardProps {
|
||||
@@ -37,31 +37,9 @@ interface EnvelopeCardProps {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Color helpers — matches SendAnimation
|
||||
// Color helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function blendHex(hex1: string, hex2: string, amount: number): string {
|
||||
const [r1, g1, b1] = hexToRgb(hex1);
|
||||
const [r2, g2, b2] = hexToRgb(hex2);
|
||||
return rgbToHex(
|
||||
Math.round(r1 + (r2 - r1) * amount),
|
||||
Math.round(g1 + (g2 - g1) * amount),
|
||||
Math.round(b1 + (b2 - b1) * amount),
|
||||
);
|
||||
}
|
||||
|
||||
function darkenHex(hex: string, amount: number): string {
|
||||
const [r, g, b] = hexToRgb(hex);
|
||||
const dark = (c: number) => Math.max(0, Math.round(c * (1 - amount)));
|
||||
return rgbToHex(dark(r), dark(g), dark(b));
|
||||
}
|
||||
|
||||
function lightenHex(hex: string, amount: number): string {
|
||||
const [r, g, b] = hexToRgb(hex);
|
||||
const light = (c: number) => Math.min(255, Math.round(c + (255 - c) * amount));
|
||||
return rgbToHex(light(r), light(g), light(b));
|
||||
}
|
||||
|
||||
function deriveColors(bgHex: string, primaryHex: string) {
|
||||
const body = blendHex(bgHex, primaryHex, 0.08);
|
||||
const isDark = hexLuminance(body) < 0.45;
|
||||
@@ -114,7 +92,7 @@ export function EnvelopeCard({ letter, mode, index, onClick }: EnvelopeCardProps
|
||||
const timeStr = shortTimeAgo(letter.timestamp);
|
||||
|
||||
const stationery = decrypted?.stationery;
|
||||
const resolved = useMemo(() => resolveStationery(stationery ?? { color: '#F5E6D3' }), [stationery]);
|
||||
const resolved = useMemo(() => resolveStationery(stationery ?? { color: DEFAULT_STATIONERY_COLOR }), [stationery]);
|
||||
const bgColor = resolved.color;
|
||||
const primaryColor = resolved.primaryColor ?? resolved.colors?.[0] ?? bgColor;
|
||||
const C = useMemo(() => deriveColors(bgColor, primaryColor), [bgColor, primaryColor]);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useNostrPublish } from '@/hooks/useNostrPublish';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from '@/hooks/useToast';
|
||||
import { genUserName } from '@/lib/genUserName';
|
||||
import { FONT_OPTIONS, LETTER_KIND, type Letter } from '@/lib/letterTypes';
|
||||
import { FONT_OPTIONS, LETTER_KIND, LINE_HEIGHT_RATIO, type Letter } from '@/lib/letterTypes';
|
||||
import { StationeryBackground } from './StationeryBackground';
|
||||
import { useStationeryColors } from '@/hooks/useStationeryColors';
|
||||
import { LetterStickers } from './LetterStickers';
|
||||
@@ -110,7 +110,7 @@ export function LetterCard({ letter, mode }: LetterCardProps) {
|
||||
cancelAnimationFrame(raf);
|
||||
raf = requestAnimationFrame(() => {
|
||||
const w = entry.contentBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
|
||||
setLineHeightPx(Math.round(w * 0.084));
|
||||
setLineHeightPx(Math.round(w * LINE_HEIGHT_RATIO));
|
||||
});
|
||||
});
|
||||
ro.observe(el);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { Loader2, Lock } from 'lucide-react';
|
||||
import { useDecryptLetter } from '@/hooks/useLetters';
|
||||
import { FONT_OPTIONS, type Letter } from '@/lib/letterTypes';
|
||||
import { FONT_OPTIONS, LINE_HEIGHT_RATIO, type Letter } from '@/lib/letterTypes';
|
||||
import { StationeryBackground } from './StationeryBackground';
|
||||
import { useStationeryColors } from '@/hooks/useStationeryColors';
|
||||
import { LetterStickers } from './LetterStickers';
|
||||
@@ -18,11 +18,10 @@ import {
|
||||
|
||||
interface LetterDetailSheetProps {
|
||||
letter: Letter | null;
|
||||
mode: 'inbox' | 'sent';
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function LetterDetailSheet({ letter, mode, onClose }: LetterDetailSheetProps) {
|
||||
export function LetterDetailSheet({ letter, onClose }: LetterDetailSheetProps) {
|
||||
const letterRef = useRef<HTMLDivElement>(null);
|
||||
const [lineHeightPx, setLineHeightPx] = useState(0);
|
||||
|
||||
@@ -47,7 +46,7 @@ export function LetterDetailSheet({ letter, mode, onClose }: LetterDetailSheetPr
|
||||
const el = letterRef.current;
|
||||
if (!el) return;
|
||||
const w = el.getBoundingClientRect().width;
|
||||
if (w > 0) setLineHeightPx(Math.round(w * 0.084));
|
||||
if (w > 0) setLineHeightPx(Math.round(w * LINE_HEIGHT_RATIO));
|
||||
}, 50);
|
||||
|
||||
const el = letterRef.current;
|
||||
@@ -58,7 +57,7 @@ export function LetterDetailSheet({ letter, mode, onClose }: LetterDetailSheetPr
|
||||
cancelAnimationFrame(raf);
|
||||
raf = requestAnimationFrame(() => {
|
||||
const w = entry.contentBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
|
||||
if (w > 0) setLineHeightPx(Math.round(w * 0.084));
|
||||
if (w > 0) setLineHeightPx(Math.round(w * LINE_HEIGHT_RATIO));
|
||||
});
|
||||
});
|
||||
ro.observe(el);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { TabButton } from '@/components/TabButton';
|
||||
import {
|
||||
FONT_OPTIONS,
|
||||
CLOSING_PRESETS,
|
||||
LINE_HEIGHT_RATIO,
|
||||
type Stationery,
|
||||
type FrameStyle,
|
||||
} from '@/lib/letterTypes';
|
||||
@@ -133,7 +134,7 @@ export function LetterEditor({
|
||||
if (!el) return;
|
||||
const ro = new ResizeObserver(([entry]) => {
|
||||
const w = entry.contentBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
|
||||
setLineHeightPx(Math.round(w * 0.084));
|
||||
setLineHeightPx(Math.round(w * LINE_HEIGHT_RATIO));
|
||||
});
|
||||
ro.observe(el);
|
||||
return () => ro.disconnect();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { useState, useRef, useEffect, useMemo } from 'react';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import { Loader2, X } from 'lucide-react';
|
||||
import { useSearchProfiles, type SearchProfile } from '@/hooks/useSearchProfiles';
|
||||
@@ -27,7 +27,8 @@ export function LetterRecipientInput({ onSelect, initialNpub, friendsOnly = fals
|
||||
|
||||
const { data: searchResults, isLoading } = useSearchProfiles(selected ? '' : query);
|
||||
const followListData = useFollowList();
|
||||
const followedPubkeys = new Set(followListData.data?.pubkeys ?? []);
|
||||
const followPubkeyArray = followListData.data?.pubkeys;
|
||||
const followedPubkeys = useMemo(() => new Set(followPubkeyArray ?? []), [followPubkeyArray]);
|
||||
|
||||
const profiles = (() => {
|
||||
const all = searchResults ?? [];
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
import { useId, useRef, useEffect, useLayoutEffect, useCallback, useState, useMemo } from 'react';
|
||||
import { hexToRgb, rgbToHex } from '@/lib/colorUtils';
|
||||
import { hexToRgb, rgbToHex, darkenHex, blendHex } from '@/lib/colorUtils';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Easing + animation driver
|
||||
@@ -79,22 +79,6 @@ function mixHex(hex: string, lightAmount: number): string {
|
||||
return rgbToHex(mix(r), mix(g), mix(b));
|
||||
}
|
||||
|
||||
function darkenHex(hex: string, amount: number): string {
|
||||
const [r, g, b] = hexToRgb(hex);
|
||||
const dark = (c: number) => Math.max(0, Math.round(c * (1 - amount)));
|
||||
return rgbToHex(dark(r), dark(g), dark(b));
|
||||
}
|
||||
|
||||
function blendHex(hex: string, targetHex: string, amount: number): string {
|
||||
const [r1, g1, b1] = hexToRgb(hex);
|
||||
const [r2, g2, b2] = hexToRgb(targetHex);
|
||||
return rgbToHex(
|
||||
Math.round(r1 + (r2 - r1) * amount),
|
||||
Math.round(g1 + (g2 - g1) * amount),
|
||||
Math.round(b1 + (b2 - b1) * amount),
|
||||
);
|
||||
}
|
||||
|
||||
function envelopeColors(bgHex: string, primaryHex: string) {
|
||||
// Tint the envelope body slightly toward the primary color so it
|
||||
// contrasts with the raw background even on matching themes.
|
||||
|
||||
@@ -13,17 +13,18 @@
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
FRAME_PRESETS,
|
||||
DEFAULT_STATIONERY_COLOR,
|
||||
type Stationery,
|
||||
type ResolvedStationery,
|
||||
type FrameStyle,
|
||||
resolveStationery,
|
||||
} from '@/lib/letterTypes';
|
||||
import { ColorPaletteDisplay, type PaletteLayout } from './ColorPaletteDisplay';
|
||||
import { hexLuminance } from '@/lib/colorUtils';
|
||||
import { hexLuminance, darkenHex } from '@/lib/colorUtils';
|
||||
|
||||
export type { PaletteLayout } from './ColorPaletteDisplay';
|
||||
|
||||
const DEFAULT_STATIONERY: Stationery = { color: '#F5E6D3' };
|
||||
const DEFAULT_STATIONERY: Stationery = { color: DEFAULT_STATIONERY_COLOR };
|
||||
|
||||
function frameTintColor(resolved: ResolvedStationery): string {
|
||||
if (resolved.primaryColor) return resolved.primaryColor;
|
||||
@@ -31,18 +32,6 @@ function frameTintColor(resolved: ResolvedStationery): string {
|
||||
return resolved.color ?? '#3a7a3a';
|
||||
}
|
||||
|
||||
function darkenHex(hex: string, amount: number): string {
|
||||
if (!hex) return '#000000';
|
||||
const r = parseInt(hex.slice(1, 3), 16);
|
||||
const g = parseInt(hex.slice(3, 5), 16);
|
||||
const b = parseInt(hex.slice(5, 7), 16);
|
||||
const f = 1 - amount;
|
||||
const dr = Math.round(r * f);
|
||||
const dg = Math.round(g * f);
|
||||
const db = Math.round(b * f);
|
||||
return `#${dr.toString(16).padStart(2, '0')}${dg.toString(16).padStart(2, '0')}${db.toString(16).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
interface EmojiFrameProps {
|
||||
tint: string | null;
|
||||
thickness: number;
|
||||
|
||||
@@ -244,7 +244,8 @@ export function StationeryPicker({ selected, onSelect }: StationeryPickerProps)
|
||||
|
||||
const { user } = useCurrentUser();
|
||||
const followListData = useFollowList();
|
||||
const followList = new Set(followListData.data?.pubkeys ?? []);
|
||||
const followPubkeyArray = followListData.data?.pubkeys;
|
||||
const followList = useMemo(() => new Set(followPubkeyArray ?? []), [followPubkeyArray]);
|
||||
|
||||
const scopedAuthors = useMemo(() => {
|
||||
if (scope === 'mine') return user ? [user.pubkey] : undefined;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMemo } from 'react';
|
||||
import { type Stationery, resolveStationery } from '@/lib/letterTypes';
|
||||
import { type Stationery, resolveStationery, DEFAULT_STATIONERY_COLOR } from '@/lib/letterTypes';
|
||||
import {
|
||||
paletteTextColor,
|
||||
paletteTextColorFaint,
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from '@/lib/colorUtils';
|
||||
|
||||
/** Default stationery when none is provided */
|
||||
const DEFAULT_STATIONERY: Stationery = { color: '#F5E6D3' };
|
||||
const DEFAULT_STATIONERY: Stationery = { color: DEFAULT_STATIONERY_COLOR };
|
||||
|
||||
/**
|
||||
* useStationeryColors
|
||||
|
||||
@@ -207,6 +207,33 @@ export function tokensToCoreColors(tokens: ThemeTokens): CoreThemeColors {
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Hex color manipulation ───────────────────────────────────────────
|
||||
|
||||
/** Darken a hex color by a factor (0 = no change, 1 = black). */
|
||||
export function darkenHex(hex: string, amount: number): string {
|
||||
const [r, g, b] = hexToRgb(hex);
|
||||
const dark = (c: number) => Math.max(0, Math.round(c * (1 - amount)));
|
||||
return rgbToHex(dark(r), dark(g), dark(b));
|
||||
}
|
||||
|
||||
/** Lighten a hex color by a factor (0 = no change, 1 = white). */
|
||||
export function lightenHex(hex: string, amount: number): string {
|
||||
const [r, g, b] = hexToRgb(hex);
|
||||
const light = (c: number) => Math.min(255, Math.round(c + (255 - c) * amount));
|
||||
return rgbToHex(light(r), light(g), light(b));
|
||||
}
|
||||
|
||||
/** Blend two hex colors by a factor (0 = hex1, 1 = hex2). */
|
||||
export function blendHex(hex1: string, hex2: string, amount: number): string {
|
||||
const [r1, g1, b1] = hexToRgb(hex1);
|
||||
const [r2, g2, b2] = hexToRgb(hex2);
|
||||
return rgbToHex(
|
||||
Math.round(r1 + (r2 - r1) * amount),
|
||||
Math.round(g1 + (g2 - g1) * amount),
|
||||
Math.round(b1 + (b2 - b1) * amount),
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Letter stationery color utilities ────────────────────────────────
|
||||
|
||||
/** WCAG 2.1 relative luminance of a hex color (0 = black, 1 = white). */
|
||||
|
||||
@@ -4,6 +4,12 @@ export const LETTER_KIND = 8211;
|
||||
export const COLOR_MOMENT_KIND = 3367;
|
||||
export const THEME_KIND = 36767;
|
||||
|
||||
/** Default stationery background color (parchment). */
|
||||
export const DEFAULT_STATIONERY_COLOR = '#F5E6D3';
|
||||
|
||||
/** Ratio of ruled-line height to card width. Used across letter rendering components. */
|
||||
export const LINE_HEIGHT_RATIO = 0.084;
|
||||
|
||||
/** A sticker placed on top of the letter card */
|
||||
export interface LetterSticker {
|
||||
/** Image URL of the sticker (empty string for drawn stickers) */
|
||||
@@ -203,7 +209,7 @@ export interface Letter {
|
||||
* No gradients.
|
||||
*/
|
||||
export const STATIONERY_PRESETS: Record<string, { name: string; color: string; emoji?: string }> = {
|
||||
parchment: { name: 'Parchment', color: '#F5E6D3', emoji: undefined },
|
||||
parchment: { name: 'Parchment', color: DEFAULT_STATIONERY_COLOR, emoji: undefined },
|
||||
meadow: { name: 'Meadow', color: '#C8E6C9', emoji: '🌿' },
|
||||
twilight: { name: 'Twilight', color: '#E1BEE7', emoji: '🌙' },
|
||||
ocean: { name: 'Ocean', color: '#B3E5FC', emoji: '🌊' },
|
||||
@@ -276,12 +282,12 @@ export function presetToStationery(key: string): Stationery | undefined {
|
||||
|
||||
/** Build a Stationery from a kind 3367 color moment event. */
|
||||
export function colorMomentToStationery(event: NostrEvent): Stationery {
|
||||
const color = event.tags.find(([n]) => n === 'c')?.[1] ?? '#F5E6D3';
|
||||
const color = event.tags.find(([n]) => n === 'c')?.[1] ?? DEFAULT_STATIONERY_COLOR;
|
||||
return { color, event };
|
||||
}
|
||||
|
||||
/** Build a Stationery from a kind 36767 theme event. */
|
||||
export function themeToStationery(event: NostrEvent): Stationery {
|
||||
const bg = event.tags.filter(([n]) => n === 'c').find(([, , marker]) => marker === 'background');
|
||||
return { color: bg?.[1] ?? '#F5E6D3', event };
|
||||
return { color: bg?.[1] ?? DEFAULT_STATIONERY_COLOR, event };
|
||||
}
|
||||
|
||||
@@ -159,7 +159,6 @@ export function LettersPage() {
|
||||
{/* Letter detail drawer */}
|
||||
<LetterDetailSheet
|
||||
letter={selectedLetter}
|
||||
mode={tab}
|
||||
onClose={() => setSelectedLetter(null)}
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user