Skip to content

Commit

Permalink
Reimplement UI using EUI components
Browse files Browse the repository at this point in the history
  • Loading branch information
bryophyta committed Sep 12, 2024
1 parent 9eb60c0 commit 4b8dec7
Show file tree
Hide file tree
Showing 8 changed files with 400 additions and 282 deletions.
11 changes: 6 additions & 5 deletions newswires/app/db/FingerpostWireEntry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,14 @@ object FingerpostWireEntry extends SQLSyntaxSupport[FingerpostWireEntry] {
sqls"$query <% (${FingerpostWireEntry.syn.column("content")}->>$fieldName)"

val headline = filterElement("headline")
val subhead = filterElement("subhead")
val byline = filterElement("byline")
val keywords = filterElement("keywords")
val bodyText = filterElement("body_text")
// val subhead = filterElement("subhead")
// val byline = filterElement("byline")
// val keywords = filterElement("keywords")
// val bodyText = filterElement("body_text")

val filters =
sqls"$headline OR $subhead OR $byline OR $keywords OR $bodyText"
sqls"$headline"
// sqls"$headline OR $subhead OR $byline OR $keywords OR $bodyText"

sql"""| SELECT ${FingerpostWireEntry.syn.result.*}
| FROM ${FingerpostWireEntry as syn}
Expand Down
44 changes: 0 additions & 44 deletions newswires/client/src/App.css

This file was deleted.

196 changes: 40 additions & 156 deletions newswires/client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { css } from '@emotion/react';
import {
EuiFieldSearch,
EuiHeader,
EuiHeaderSectionItem,
EuiLoadingLogo,
EuiPageTemplate,
EuiProvider,
EuiTitle,
} from '@elastic/eui';
import { useEffect, useMemo, useState } from 'react';
import sanitizeHtml from 'sanitize-html';
import './App.css';
import '@elastic/eui/dist/eui_theme_light.css';
import { WireCardList } from './WiresCards';

type WireData = {
export type WireData = {
id: number;
externalId: string;
ingestedAt: string;
Expand Down Expand Up @@ -53,14 +61,6 @@ export function App() {

const [query, setQuery] = useState<string>('');

const [selected, setSelected] = useState<WireData | undefined>(undefined);

const safeBodyText = useMemo(() => {
return selected?.content.body_text
? sanitizeHtml(selected.content.body_text)
: undefined;
}, [selected]);

const updateQuery = useMemo(() => debounce(setQuery, 750), []);

useEffect(() => {
Expand All @@ -81,149 +81,33 @@ export function App() {
}, [query]);

return (
<div
css={css`
display: flex;
flex-direction: column;
height: 100%;
`}
>
<div
css={css`
display: flex;
flex-direction: row;
justify-content: space-between;
`}
>
<h1
css={css`
height: fit-content;
margin: 0;
border: 1px solid black;
`}
>
Newswires
</h1>
<span
css={css`
display: flex;
flex-direction: row;
gap: 4px;
`}
>
<label>Search</label>
<input type="text" onChange={(e) => updateQuery(e.target.value)} />
</span>
</div>
<div
css={css`
border: 1px solid black;
min-height: 25vh;
flex-grow: 1;
overflow-y: scroll;
`}
>
{'error' in pageState && (
<p>Sorry, failed to load because of {pageState.error}</p>
)}
{'loading' in pageState && <p>Loading, please wait...</p>}
{Array.isArray(pageState) && (
<ul
css={css`
padding: 0;
margin: 0;
`}
>
{pageState.map((item) => (
<li
css={css`
list-style: none;
user-select: none;
cursor: pointer;
margin: 10px;
padding: 10px;
border-radius: 5px;
background-color: #dcdcdc;
&:nth-child(even) {
background-color: #c0c0c0;
}
`}
key={item.id}
onClick={() => setSelected(item)}
>
{item.content.headline ?? '<missing headline>'}
</li>
))}
</ul>
)}
</div>
{selected && (
<div
css={css`
border: 1px solid black;
flex-grow: 1;
overflow-y: scroll;
padding: 10px;
`}
>
<button onClick={() => setSelected(undefined)}>X</button>
<article>
{selected.content.headline && <h2>{selected.content.headline}</h2>}
{selected.content.subhead &&
selected.content.subhead !== selected.content.headline && (
<h3>{selected.content.subhead}</h3>
)}
{selected.content.byline && (
<p>
By: <address>{selected.content.byline}</address>
</p>
)}
{selected.content.keywords && (
<p>
<span
css={css`
font-style: italic;
`}
>
Keywords:{' '}
</span>
{selected.content.keywords}
</p>
)}
{selected.content.usage && (
<p>
<span
css={css`
font-style: italic;
`}
>
Usage restrictions:
</span>{' '}
<span
css={css`
font-weight: bold;
`}
>
{selected.content.usage}
</span>
</p>
)}
<hr />
{selected.content.location && (
<p
css={css`
font-weight: bold;
`}
>
{selected.content.location}
</p>
)}
{safeBodyText && (
<article dangerouslySetInnerHTML={{ __html: safeBodyText }} />
)}
</article>
</div>
)}
</div>
<EuiProvider colorMode="light">
<EuiPageTemplate>
<EuiHeader position="fixed">
<EuiHeaderSectionItem>
<EuiTitle size={'s'}>
<h1>Newswires</h1>
</EuiTitle>
</EuiHeaderSectionItem>
<EuiHeaderSectionItem>
<EuiFieldSearch onChange={(e) => updateQuery(e.target.value)} />
</EuiHeaderSectionItem>
</EuiHeader>
<EuiPageTemplate.Section>
{'error' in pageState && (
<EuiPageTemplate.EmptyPrompt>
<p>Sorry, failed to load because of {pageState.error}</p>
</EuiPageTemplate.EmptyPrompt>
)}
{'loading' in pageState && (
<EuiPageTemplate.EmptyPrompt
icon={<EuiLoadingLogo logo="clock" size="xl" />}
title={<h2>Loading Wires</h2>}
/>
)}
{Array.isArray(pageState) && <WireCardList wires={pageState} />}
</EuiPageTemplate.Section>
</EuiPageTemplate>
</EuiProvider>
);
}
Loading

0 comments on commit 4b8dec7

Please sign in to comment.