Add web interface and tests

This commit is contained in:
aet
2021-11-05 03:17:18 -04:00
parent 7f41a50fb1
commit fe926be0a6
66 changed files with 3390 additions and 1275 deletions

View File

@ -0,0 +1,103 @@
import styled from "@emotion/styled"
import type { ItemSection, ItemField } from "opvault.js"
import { FieldType } from "opvault.js"
import { useCallback, useMemo, useState } from "react"
import { parseMonthYear } from "../utils"
import { ErrorBoundary } from "./ErrorBoundary"
import { useItemFieldContextMenu } from "./ItemFieldContextMenu"
const Container = styled.div``
const Password: React.FC<{
field: ItemSection.Concealed
}> = ({ field }) => {
const [show, setShow] = useState(false)
const { onRightClick, ContextMenuContainer, Item } = useItemFieldContextMenu()
const onToggle = useCallback(() => setShow(x => !x), [])
const onCopy = useCallback(() => {
navigator.clipboard.writeText(field.v)
}, [field.v])
return (
<>
<Container
onContextMenu={onRightClick}
onDoubleClick={() => setShow(x => !x)}
style={{
fontFamily: "var(--monospace)",
...(!show && { userSelect: "none" }),
}}
>
{show ? field.v : "·".repeat(10)}
</Container>
<ContextMenuContainer>
<Item onClick={onCopy}>Copier</Item>
<Item onClick={onToggle}>{show ? "Cacher" : "Afficher"}</Item>
</ContextMenuContainer>
</>
)
}
const MonthYear: React.FC<{ field: ItemSection.MonthYear }> = ({ field }) => {
const { year, month } = parseMonthYear(field.v)
return (
<Container>
{month.toString().padStart(2, "0")}/{year.toString().padStart(4, "0")}
</Container>
)
}
const DateView: React.FC<{ field: ItemSection.Date }> = ({ field }) => {
const date = useMemo(() => new Date(field.v * 1000), [field.v])
return <Container>{date.toLocaleDateString()}</Container>
}
export const ItemFieldValue: React.FC<{
field: ItemSection.Any
}> = ({ field }) => {
if (field.v == null) {
return null
}
switch (field.k) {
case "concealed":
return <Password field={field} />
case "monthYear":
return <MonthYear field={field} />
case "date":
return <DateView field={field} />
case "address":
return (
<Container style={{ whiteSpace: "pre" }}>
<div>{field.v.street}</div>
<div>
{field.v.city}, {field.v.state} ({field.v.zip})
</div>
<div>{field.v.country}</div>
</Container>
)
}
return (
<ErrorBoundary>
<Container>{field.v}</Container>
</ErrorBoundary>
)
}
export const ItemDetailsFieldValue: React.FC<{
field: ItemField
}> = ({ field }) => {
if (
field.type === FieldType.Password ||
(field.type === FieldType.Text && field.designation === "password")
) {
return <Password field={{ v: field.value } as any} />
}
return (
<ErrorBoundary>
<Container>{field.value}</Container>
</ErrorBoundary>
)
}