143 lines
3.5 KiB
TypeScript
143 lines
3.5 KiB
TypeScript
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>
|
|
}
|