mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #3596 from omnivore-app/fix/web-layout-fixes
Small layout fixes for mobile
This commit is contained in:
commit
a74377556b
7 changed files with 96 additions and 26 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ export const FormInput = styled('input', {
|
|||
'&:focus': {
|
||||
outline: 'none',
|
||||
},
|
||||
'@mdDown': {
|
||||
pl: '5px',
|
||||
},
|
||||
})
|
||||
|
||||
export const FormLabel = styled('label', {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
</StyledText>
|
||||
<StyledText
|
||||
<SpanBox
|
||||
css={{
|
||||
display: 'flex',
|
||||
marginBlockStart: '0px',
|
||||
marginBlockEnd: '0px',
|
||||
fontSize: '15px',
|
||||
lineHeight: '125%',
|
||||
fontFamily: '$inter',
|
||||
color: '$thTextSubtle2',
|
||||
whiteSpace: 'nowrap',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
We have encountered unexpected problems.{' '}
|
||||
|
|
@ -50,7 +50,7 @@ export const FetchItemsError = (): JSX.Element => {
|
|||
>
|
||||
Get help
|
||||
</a>
|
||||
</StyledText>
|
||||
</SpanBox>
|
||||
</VStack>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<>
|
||||
<SpanBox
|
||||
css={{
|
||||
display: 'none',
|
||||
'@mdDown': { display: 'flex' },
|
||||
}}
|
||||
>
|
||||
<MenuHeaderButton {...props} />
|
||||
</SpanBox>
|
||||
{!searchBoxFocused && (
|
||||
<SpanBox
|
||||
css={{
|
||||
display: 'none',
|
||||
'@mdDown': { display: 'flex' },
|
||||
}}
|
||||
>
|
||||
<MenuHeaderButton {...props} />
|
||||
</SpanBox>
|
||||
)}
|
||||
|
||||
<SearchBox {...props} />
|
||||
<SearchBox
|
||||
{...props}
|
||||
searchBoxFocused={searchBoxFocused}
|
||||
setSearchBoxFocused={setSearchBoxFocused}
|
||||
/>
|
||||
|
||||
<SpanBox css={{ display: 'flex', ml: 'auto', gap: '10px' }}>
|
||||
{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<HTMLInputElement | null>(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)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ export const MultiSelectControls = (props: LibraryHeaderProps): JSX.Element => {
|
|||
const [hoverColor, setHoverColor] = useState<string>(
|
||||
theme.colors.thTextContrast2.toString()
|
||||
)
|
||||
const compact = false
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
|
@ -45,7 +44,7 @@ export const MultiSelectControls = (props: LibraryHeaderProps): JSX.Element => {
|
|||
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',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<SpanBox
|
||||
css={{
|
||||
display: 'flex',
|
||||
fontSize: '14px',
|
||||
fontFamily: '$display',
|
||||
marginRight: 'auto',
|
||||
'@mdDown': {
|
||||
display: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{props.numItemsSelected} items selected
|
||||
</SpanBox>
|
||||
<SpanBox
|
||||
css={{
|
||||
display: 'none',
|
||||
fontSize: '14px',
|
||||
fontFamily: '$display',
|
||||
marginRight: 'auto',
|
||||
'@mdDown': {
|
||||
display: 'flex',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{props.numItemsSelected} items
|
||||
</SpanBox>
|
||||
<ArchiveButton {...props} />
|
||||
<AddLabelsButton setShowLabelsModal={setShowLabelsModal} />
|
||||
<RemoveItemsButton setShowConfirmDelete={setShowConfirmDelete} />
|
||||
|
|
|
|||
|
|
@ -58,11 +58,14 @@ export function TLDRLayout(props: TLDRLayoutProps): JSX.Element {
|
|||
{props.isValidating && props.items.length == 0 && <TopBarProgress />}
|
||||
|
||||
{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 (
|
||||
<VStack key={`tldr-${item.node.id}`} css={{ gap: '10px' }}>
|
||||
<HStack
|
||||
|
|
@ -96,6 +99,12 @@ export function TLDRLayout(props: TLDRLayoutProps): JSX.Element {
|
|||
display: 'flex',
|
||||
fontFamily: '$inter',
|
||||
fontSize: '16px',
|
||||
maxWidth: '150px',
|
||||
maxLines: '1',
|
||||
textOverflow: 'ellipsis',
|
||||
'@mdDown': {
|
||||
fontSize: '12px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
{item.node.siteName}
|
||||
|
|
@ -104,9 +113,14 @@ export function TLDRLayout(props: TLDRLayoutProps): JSX.Element {
|
|||
{source && item.node.author && (
|
||||
<SpanBox
|
||||
css={{
|
||||
maxLines: '1',
|
||||
display: 'flex',
|
||||
fontFamily: '$inter',
|
||||
fontSize: '16px',
|
||||
maxWidth: '150px',
|
||||
textOverflow: 'ellipsis',
|
||||
'@mdDown': {
|
||||
fontSize: '12px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
•
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
Loading…
Reference in a new issue