diff --git a/packages/api/src/jobs/ai-summarize.ts b/packages/api/src/jobs/ai-summarize.ts index 64cef703c..974a6b347 100644 --- a/packages/api/src/jobs/ai-summarize.ts +++ b/packages/api/src/jobs/ai-summarize.ts @@ -7,6 +7,7 @@ import { libraryItemRepository } from '../repository/library_item' import { htmlToMarkdown } from '../utils/parser' import { AISummary } from '../entity/AISummary' import { LibraryItemState } from '../entity/library_item' +import { getAISummary } from '../services/ai-summaries' export interface AISummarizeJobData { userId: string @@ -35,6 +36,19 @@ export const aiSummarize = async (jobData: AISummarizeJobData) => { return } + const existingSummary = await getAISummary({ + userId: jobData.userId, + idx: 'latest', + libraryItemId: jobData.libraryItemId, + }) + + if (existingSummary) { + logger.info( + `Library item already has a summary: ${jobData.libraryItemId}` + ) + return + } + const llm = new ChatOpenAI({ configuration: { apiKey: process.env.OPENAI_API_KEY, diff --git a/packages/web/components/elements/FormElements.tsx b/packages/web/components/elements/FormElements.tsx index d2e3c7691..b672989bf 100644 --- a/packages/web/components/elements/FormElements.tsx +++ b/packages/web/components/elements/FormElements.tsx @@ -41,6 +41,9 @@ export const FormInput = styled('input', { '&:focus': { outline: 'none', }, + '@mdDown': { + pl: '5px', + }, }) export const FormLabel = styled('label', { diff --git a/packages/web/components/patterns/LibraryCards/LibraryGridCard.tsx b/packages/web/components/patterns/LibraryCards/LibraryGridCard.tsx index e2dc59569..c824c82e9 100644 --- a/packages/web/components/patterns/LibraryCards/LibraryGridCard.tsx +++ b/packages/web/components/patterns/LibraryCards/LibraryGridCard.tsx @@ -74,9 +74,11 @@ export function LibraryGridCard(props: LinkedItemCardProps): JSX.Element { overflow: 'hidden', cursor: 'pointer', '@media (max-width: 930px)': { - // m: '15px', width: 'calc(100% - 30px)', }, + '@mdDown': { + width: '100%', + }, }} alignment="start" distribution="start" diff --git a/packages/web/components/templates/homeFeed/FetchItemsError.tsx b/packages/web/components/templates/homeFeed/FetchItemsError.tsx index 7a6f1c2d9..d96c7f8b5 100644 --- a/packages/web/components/templates/homeFeed/FetchItemsError.tsx +++ b/packages/web/components/templates/homeFeed/FetchItemsError.tsx @@ -1,4 +1,4 @@ -import { VStack } from '../../elements/LayoutPrimitives' +import { Box, SpanBox, VStack } from '../../elements/LayoutPrimitives' import { StyledText } from '../../elements/StyledText' import { ErrorSlothIcon } from '../../elements/icons/ErrorSlothIcon' import { DEFAULT_HEADER_HEIGHT } from './HeaderSpacer' @@ -13,6 +13,7 @@ export const FetchItemsError = (): JSX.Element => { width: '100%', height: '100%', pb: '100px', + px: '30px', minHeight: `calc(100vh - ${DEFAULT_HEADER_HEIGHT})`, }} > @@ -30,16 +31,15 @@ export const FetchItemsError = (): JSX.Element => { > Something has gone wrong. - We have encountered unexpected problems.{' '} @@ -50,7 +50,7 @@ export const FetchItemsError = (): JSX.Element => { > Get help - + ) } diff --git a/packages/web/components/templates/homeFeed/LibraryHeader.tsx b/packages/web/components/templates/homeFeed/LibraryHeader.tsx index 93e97ba97..26efa348b 100644 --- a/packages/web/components/templates/homeFeed/LibraryHeader.tsx +++ b/packages/web/components/templates/homeFeed/LibraryHeader.tsx @@ -49,7 +49,6 @@ export const headerControlWidths = ( return { width: '95%', '@mdDown': { - padding: '15px', width: '100%', }, '@media (min-width: 930px)': { @@ -135,18 +134,26 @@ function LargeHeaderLayout(props: LibraryHeaderProps): JSX.Element { } const HeaderControls = (props: LibraryHeaderProps): JSX.Element => { + const [searchBoxFocused, setSearchBoxFocused] = useState(false) + return ( <> - - - + {!searchBoxFocused && ( + + + + )} - + {userHasFeature(props.viewer, 'ai-summaries') && ( @@ -243,9 +250,13 @@ export function MenuHeaderButton(props: MenuHeaderButtonProps): JSX.Element { ) } -export function SearchBox(props: LibraryHeaderProps): JSX.Element { +type SearchBoxProps = LibraryHeaderProps & { + searchBoxFocused: boolean + setSearchBoxFocused: (show: boolean) => void +} + +export function SearchBox(props: SearchBoxProps): JSX.Element { const inputRef = useRef(null) - const [focused, setFocused] = useState(false) const [searchTerm, setSearchTerm] = useState(props.searchTerm ?? '') useEffect(() => { @@ -272,7 +283,7 @@ export function SearchBox(props: LibraryHeaderProps): JSX.Element { maxWidth: '521px', bg: '$thLibrarySearchbox', borderRadius: '6px', - boxShadow: focused + boxShadow: props.searchBoxFocused ? 'none' : '0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);', }} @@ -306,7 +317,7 @@ export function SearchBox(props: LibraryHeaderProps): JSX.Element { alignment="center" distribution="start" css={{ - border: focused + border: props.searchBoxFocused ? '2px solid $searchActiveOutline' : '2px solid transparent', borderTopRightRadius: '6px', @@ -331,10 +342,10 @@ export function SearchBox(props: LibraryHeaderProps): JSX.Element { placeholder="Search keywords or labels" onFocus={(event) => { event.target.select() - setFocused(true) + props.setSearchBoxFocused(true) }} onBlur={() => { - setFocused(false) + props.setSearchBoxFocused(false) }} onChange={(event) => { setSearchTerm(event.target.value) diff --git a/packages/web/components/templates/homeFeed/MultiSelectControls.tsx b/packages/web/components/templates/homeFeed/MultiSelectControls.tsx index 4361bef88..987889182 100644 --- a/packages/web/components/templates/homeFeed/MultiSelectControls.tsx +++ b/packages/web/components/templates/homeFeed/MultiSelectControls.tsx @@ -21,7 +21,6 @@ export const MultiSelectControls = (props: LibraryHeaderProps): JSX.Element => { const [hoverColor, setHoverColor] = useState( theme.colors.thTextContrast2.toString() ) - const compact = false return ( { css={{ width: '100%', height: '100%', - pr: compact ? '5px' : '10px', + pr: '10px', }} onClick={(e) => { e.preventDefault() @@ -81,17 +80,37 @@ export const MultiSelectControls = (props: LibraryHeaderProps): JSX.Element => { border: '2px solid transparent', width: '100%', height: '100%', + '@mdDown': { + pl: '5px', + }, }} > {props.numItemsSelected} items selected + + {props.numItemsSelected} items + diff --git a/packages/web/components/templates/homeFeed/TLDRLayout.tsx b/packages/web/components/templates/homeFeed/TLDRLayout.tsx index 53eafdc00..29a3a26cc 100644 --- a/packages/web/components/templates/homeFeed/TLDRLayout.tsx +++ b/packages/web/components/templates/homeFeed/TLDRLayout.tsx @@ -58,11 +58,14 @@ export function TLDRLayout(props: TLDRLayoutProps): JSX.Element { {props.isValidating && props.items.length == 0 && } {props.items.map((item) => { - const source = siteName( + const sourceName = siteName( item.node.originalArticleUrl, item.node.url, item.node.siteName ) + const source = + sourceName == item.node.author ? undefined : item.node.author + return ( {item.node.siteName} @@ -104,9 +113,14 @@ export function TLDRLayout(props: TLDRLayoutProps): JSX.Element { {source && item.node.author && ( • @@ -118,6 +132,12 @@ export function TLDRLayout(props: TLDRLayoutProps): JSX.Element { display: 'flex', fontFamily: '$inter', fontSize: '16px', + maxWidth: '120px', + maxLines: '1', + textOverflow: 'ellipsis', + '@mdDown': { + fontSize: '12px', + }, }} > {item.node.author} @@ -145,6 +165,7 @@ export function TLDRLayout(props: TLDRLayoutProps): JSX.Element { fontFamily: '$inter', fontWeight: '700', fontSize: '20px', + wordBreak: 'break-all', textDecoration: 'underline', a: { color: '$thTLDRText',