pwa and mobile client
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import QRCode from 'qrcode';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
|
||||
import {
|
||||
BWIP_BCID,
|
||||
TWO_DIMENSIONAL_CODE_TYPES,
|
||||
bwipRenderOptions,
|
||||
cardAbbreviation,
|
||||
textColorOn,
|
||||
type AccessKeyView,
|
||||
@@ -142,16 +141,7 @@ export function CodePreview({ code, codeType }: { code: string; codeType: CodeTy
|
||||
if (!code) return { error: 'Enter a code to see the preview' };
|
||||
if (!bwipjs) return { error: 'Loading…' };
|
||||
try {
|
||||
const svg = bwipjs.toSVG({
|
||||
bcid: BWIP_BCID[codeType],
|
||||
text: code,
|
||||
scale: 3,
|
||||
...(TWO_DIMENSIONAL_CODE_TYPES.has(codeType) ? {} : { height: 14, includetext: true, textxalign: 'center' as const }),
|
||||
paddingwidth: 4,
|
||||
paddingheight: 4,
|
||||
backgroundcolor: 'FFFFFF',
|
||||
});
|
||||
return { svg };
|
||||
return { svg: bwipjs.toSVG(bwipRenderOptions(codeType, code)) };
|
||||
} catch (e) {
|
||||
return { error: String((e as Error).message ?? e).replace(/^Error:\s*/, '') };
|
||||
}
|
||||
|
||||
@@ -27,15 +27,21 @@ function Editor({ initial }: { initial?: Card }) {
|
||||
const [card, setCard] = useState<Card | undefined>(initial);
|
||||
const [fields, setFields] = useState<CardFields>(
|
||||
initial
|
||||
? { name: initial.name, color: initial.color, code: initial.code, codeType: initial.codeType }
|
||||
: { name: '', color: randomCardColor(), code: '', codeType: 'EAN13' },
|
||||
? { name: initial.name, color: initial.color, code: initial.code, codeType: initial.codeType, comment: initial.comment ?? '' }
|
||||
: { name: '', color: randomCardColor(), code: '', codeType: 'EAN13', comment: '' },
|
||||
);
|
||||
const action = useAction();
|
||||
const [saved, setSaved] = useState(false);
|
||||
|
||||
useEffect(() => setSaved(false), [fields]);
|
||||
|
||||
const dirty = !card || card.name !== fields.name || card.color !== fields.color || card.code !== fields.code || card.codeType !== fields.codeType;
|
||||
const dirty =
|
||||
!card ||
|
||||
card.name !== fields.name ||
|
||||
card.color !== fields.color ||
|
||||
card.code !== fields.code ||
|
||||
card.codeType !== fields.codeType ||
|
||||
(card.comment ?? '') !== (fields.comment ?? '');
|
||||
const set = <K extends keyof CardFields>(key: K, value: CardFields[K]) => setFields((f) => ({ ...f, [key]: value }));
|
||||
|
||||
const save = async (e: React.FormEvent) => {
|
||||
@@ -116,6 +122,17 @@ function Editor({ initial }: { initial?: Card }) {
|
||||
<textarea id="code" className="mono" rows={2} value={fields.code} onChange={(e) => set('code', e.target.value)} required />
|
||||
</div>
|
||||
<CodePreview code={fields.code} codeType={fields.codeType} />
|
||||
<div className="field">
|
||||
<label htmlFor="comment">Comment</label>
|
||||
<textarea
|
||||
id="comment"
|
||||
rows={3}
|
||||
maxLength={2000}
|
||||
placeholder="Optional, e.g. whose card it is or how to use it"
|
||||
value={fields.comment ?? ''}
|
||||
onChange={(e) => set('comment', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="row">
|
||||
<button type="submit" disabled={action.busy || (!dirty && !!card)}>
|
||||
{card ? 'Save' : 'Create card'}
|
||||
|
||||
Reference in New Issue
Block a user