Add web interface and tests
This commit is contained in:
142
packages/web/src/components/Item.tsx
Normal file
142
packages/web/src/components/Item.tsx
Normal file
@ -0,0 +1,142 @@
|
||||
import styled from "@emotion/styled"
|
||||
import type { Attachment, AttachmentMetadata, Item } from "opvault.js"
|
||||
import { useEffect, useState } from "react"
|
||||
import { CategoryIcon } from "./CategoryIcon"
|
||||
import { ItemDates } from "./ItemDates"
|
||||
import {
|
||||
ItemFieldView,
|
||||
FieldContainer,
|
||||
FieldTitle,
|
||||
ItemDetailsFieldView,
|
||||
} from "./ItemField"
|
||||
import { ItemWarning } from "./ItemWarning"
|
||||
|
||||
interface ItemViewProps {
|
||||
item: Item
|
||||
}
|
||||
|
||||
const Header = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`
|
||||
const Icon = styled(CategoryIcon)`
|
||||
font-size: 2em;
|
||||
margin-right: 5px;
|
||||
`
|
||||
const SectionTitle = styled.div`
|
||||
font-size: 85%;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
margin: 20px 0 10px;
|
||||
`
|
||||
const Tag = styled.div`
|
||||
display: inline-block;
|
||||
margin-top: 2px;
|
||||
margin-right: 5px;
|
||||
border-radius: 4px;
|
||||
padding: 3px 7px;
|
||||
background-color: var(--label-background);
|
||||
`
|
||||
const ExtraField = styled(FieldContainer)`
|
||||
margin-bottom: 20px;
|
||||
`
|
||||
|
||||
const ItemTitle = styled.h2``
|
||||
const Container = styled.div`
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0 10px;
|
||||
`
|
||||
const Inner = styled.div`
|
||||
padding: 10px 0;
|
||||
`
|
||||
const AttachmentContainer = styled.div`
|
||||
display: flex;
|
||||
margin: 5px 0;
|
||||
`
|
||||
|
||||
export const ItemView: React.FC<ItemViewProps> = ({ item }) => (
|
||||
<Container>
|
||||
<Inner>
|
||||
<ItemWarning item={item} />
|
||||
<Header>
|
||||
{item.details.fields == null}
|
||||
<Icon category={item.category} />
|
||||
<ItemTitle>{item.overview.title}</ItemTitle>
|
||||
</Header>
|
||||
<details>
|
||||
<summary>JSON</summary>
|
||||
<pre>
|
||||
{JSON.stringify({ overview: item.overview, details: item.details }, null, 2)}
|
||||
</pre>
|
||||
</details>
|
||||
|
||||
<div style={{ marginBottom: 20 }}>
|
||||
{item.details.sections
|
||||
?.filter(s => s.fields?.some(x => x.v != null))
|
||||
.map((section, i) => (
|
||||
<div key={i}>
|
||||
{section.title != null && <SectionTitle>{section.title}</SectionTitle>}
|
||||
{section.fields?.map((field, j) => (
|
||||
<ItemFieldView key={j} field={field} />
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{!!item.details.fields?.length && (
|
||||
<div style={{ marginBottom: 20 }}>
|
||||
{item.details.fields!.map((field, i) => (
|
||||
<ItemDetailsFieldView key={i} field={field} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{item.details.notesPlain != null && (
|
||||
<ExtraField>
|
||||
<FieldTitle>notes</FieldTitle>
|
||||
<div>
|
||||
<p>{item.details.notesPlain}</p>
|
||||
</div>
|
||||
</ExtraField>
|
||||
)}
|
||||
|
||||
{!!item.overview.tags?.length && (
|
||||
<ExtraField>
|
||||
<FieldTitle>tags</FieldTitle>
|
||||
<div>
|
||||
{item.overview.tags!.map((tag, i) => (
|
||||
<Tag key={i}>{tag}</Tag>
|
||||
))}
|
||||
</div>
|
||||
</ExtraField>
|
||||
)}
|
||||
|
||||
{item.attachments.length > 0 && (
|
||||
<ExtraField>
|
||||
<FieldTitle>attachments</FieldTitle>
|
||||
<div>
|
||||
{item.attachments.map((file, i) => (
|
||||
<AttachmentView key={i} file={file} />
|
||||
))}
|
||||
</div>
|
||||
</ExtraField>
|
||||
)}
|
||||
|
||||
<ExtraField>
|
||||
<ItemDates item={item} />
|
||||
</ExtraField>
|
||||
</Inner>
|
||||
</Container>
|
||||
)
|
||||
|
||||
function AttachmentView({ file }: { file: Attachment }) {
|
||||
const [metadata, setMetadata] = useState<AttachmentMetadata>()
|
||||
useEffect(() => {
|
||||
file.unlock().then(() => setMetadata(file.metadata))
|
||||
}, [file])
|
||||
|
||||
if (!metadata) return null
|
||||
|
||||
return <AttachmentContainer>{metadata.overview.filename}</AttachmentContainer>
|
||||
}
|
Reference in New Issue
Block a user