diff --git a/packages/web/components/elements/SuggestionBox.tsx b/packages/web/components/elements/SuggestionBox.tsx
new file mode 100644
index 000000000..595ce482a
--- /dev/null
+++ b/packages/web/components/elements/SuggestionBox.tsx
@@ -0,0 +1,116 @@
+import Link from 'next/link'
+import { HStack, SpanBox, VStack } from './LayoutPrimitives'
+import { ArrowRightIcon } from './icons/ArrowRightIcon'
+import { theme } from '../tokens/stitches.config'
+import { ReactNode } from 'react'
+import { Button } from './Button'
+import { CloseIcon } from './images/CloseIcon'
+
+type SuggestionBoxProps = {
+ helpMessage: string
+ helpCTAText: string | undefined
+ helpTarget: string | undefined
+
+ size?: 'large' | 'small'
+ background?: string
+
+ dismissible?: boolean
+ onDismiss?: () => void
+}
+
+type InternalOrExternalLinkProps = {
+ link: string
+ children: ReactNode
+}
+
+const InternalOrExternalLink = (props: InternalOrExternalLinkProps) => {
+ const isExternal = props.link.startsWith('https')
+
+ return (
+
+ {!isExternal ? (
+ {props.children}
+ ) : (
+
+ {props.children}
+
+ )}
+
+ )
+}
+
+export const SuggestionBox = (props: SuggestionBoxProps) => {
+ return (
+
+
+ {props.dismissible && (
+
+
+
+ )}
+ {props.helpMessage}
+ {props.helpTarget && (
+
+
+ <>{props.helpCTAText}>
+
+
+
+ )}
+
+
+ )
+}
diff --git a/packages/web/components/templates/SettingsLayout.tsx b/packages/web/components/templates/SettingsLayout.tsx
index 7ec179af3..eb5c291a7 100644
--- a/packages/web/components/templates/SettingsLayout.tsx
+++ b/packages/web/components/templates/SettingsLayout.tsx
@@ -49,7 +49,6 @@ export function SettingsLayout(props: SettingsLayoutProps): JSX.Element {
{props.children}
diff --git a/packages/web/components/templates/homeFeed/EmptyLibrary.tsx b/packages/web/components/templates/homeFeed/EmptyLibrary.tsx
index 7e342ef24..8f227a4fe 100644
--- a/packages/web/components/templates/homeFeed/EmptyLibrary.tsx
+++ b/packages/web/components/templates/homeFeed/EmptyLibrary.tsx
@@ -9,6 +9,7 @@ import { searchQuery } from '../../../lib/networking/queries/search'
import { LIBRARY_LEFT_MENU_WIDTH } from './LibraryFilterMenu'
import { LayoutType } from './HomeFeedContainer'
import { ArrowRightIcon } from '../../elements/icons/ArrowRightIcon'
+import { SuggestionBox } from '../../elements/SuggestionBox'
type EmptyLibraryProps = {
searchTerm: string | undefined
@@ -17,7 +18,13 @@ type EmptyLibraryProps = {
layoutType: LayoutType
}
-type MessageType = 'feed' | 'newsletter' | 'library'
+type MessageType =
+ | 'inbox'
+ | 'files'
+ | 'archive'
+ | 'feed'
+ | 'newsletter'
+ | 'library'
type HelpMessageProps = {
type: MessageType
@@ -83,6 +90,12 @@ const HelpMessage = (props: HelpMessageProps) => {
export const ErrorBox = (props: HelpMessageProps) => {
const errorTitle = useMemo(() => {
switch (props.type) {
+ case 'inbox':
+ return 'Your inbox is empty.'
+ case 'archive':
+ return 'You do not have any archived items.'
+ case 'files':
+ return 'No files found.'
case 'feed':
return 'You do not have any feed items matching this query.'
case 'newsletter':
@@ -116,70 +129,70 @@ export const ErrorBox = (props: HelpMessageProps) => {
)
}
-export const SuggestionBox = (props: HelpMessageProps) => {
+export const Suggestion = (props: HelpMessageProps) => {
const helpMessage = useMemo(() => {
switch (props.type) {
case 'feed':
- return 'Want to add an RSS or Atom Subscription?'
+ return ['Want to add an RSS or Atom Subscription?', 'Click Here']
+ case 'archive':
+ return [
+ 'When you are done reading something archive it and it will be saved in Omnivore forever.',
+ 'Read the Docs',
+ ]
+ case 'files':
+ return [
+ 'Drag PDFs into the library to add them to your Omnivore account.',
+ undefined,
+ ]
case 'newsletter':
- return 'Create an Omnivore email address and subscribe to newsletters.'
+ return [
+ 'Create an Omnivore email address and subscribe to newsletters.',
+ 'Click Here',
+ ]
}
- return "Add a link or read more about Omnivore's Advanced Search."
+ return [
+ "Add a link or read more about Omnivore's Advanced Search.",
+ 'Read the Docs',
+ ]
}, [props.type])
const helpTarget = useMemo(() => {
switch (props.type) {
case 'feed':
return '/settings/feeds'
+ case 'archive':
+ case 'files':
+ return undefined
+ case 'archive':
+ case 'inbox':
+ return 'https://docs.omnivore.app/using/saving'
case 'newsletter':
return '/settings/emails'
}
return 'https://docs.omnivore.app/'
}, [props.type])
+ const helpTargetWindow = useMemo(() => {
+ switch (props.type) {
+ case 'archive':
+ case 'inbox':
+ return '_blank'
+ }
+ return undefined
+ }, [props.type])
+
return (
-
- {helpMessage}
-
-
-
- <>Click Here>
-
-
-
-
-
+ <>
+ {helpMessage[0] ? (
+
+ ) : (
+ <>>
+ )}
+ >
)
}
@@ -187,6 +200,12 @@ export const EmptyLibrary = (props: EmptyLibraryProps) => {
const type = useMemo(() => {
if (props.searchTerm) {
switch (props.searchTerm) {
+ case 'in:archive':
+ return 'archive'
+ case 'in:inbox':
+ return 'inbox'
+ case 'type:file':
+ return 'files'
case 'label:RSS':
return 'feed'
case 'label:Newsletter':
@@ -205,9 +224,7 @@ export const EmptyLibrary = (props: EmptyLibraryProps) => {
pl: '0px',
width: '100%',
- '@media (max-width: 1300px)': {
- flexDirection: 'column',
- },
+ flexDirection: 'column',
'@media (max-width: 768px)': {
p: '15px',
@@ -232,7 +249,7 @@ export const EmptyLibrary = (props: EmptyLibraryProps) => {
}}
>
-
+
)
}
diff --git a/packages/web/components/templates/settings/SettingsTable.tsx b/packages/web/components/templates/settings/SettingsTable.tsx
index a71e290d1..0460ab8a0 100644
--- a/packages/web/components/templates/settings/SettingsTable.tsx
+++ b/packages/web/components/templates/settings/SettingsTable.tsx
@@ -8,6 +8,8 @@ import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
import { StyledText } from '../../elements/StyledText'
import { theme } from '../../tokens/stitches.config'
import { SettingsLayout } from '../SettingsLayout'
+import { SuggestionBox } from '../../elements/SuggestionBox'
+import { usePersistedState } from '../../../lib/hooks/usePersistedState'
type SettingsTableProps = {
pageId: string
@@ -17,6 +19,8 @@ type SettingsTableProps = {
createTitle?: string
createAction?: () => void
+ suggestionInfo: SuggestionInfo
+
children: React.ReactNode
}
@@ -52,6 +56,12 @@ type MoreOptionsProps = {
onEdit?: () => void
}
+type SuggestionInfo = {
+ text: string
+ docs: string
+ key: string
+}
+
const MoreOptions = (props: MoreOptionsProps) => (
{
}
export const SettingsTable = (props: SettingsTableProps): JSX.Element => {
+ const [showSuggestion, setShowSuggestion] = usePersistedState({
+ key: props.suggestionInfo.key,
+ initialValue: !!props.suggestionInfo,
+ })
+
return (
{
},
}}
>
+ {props.suggestionInfo && showSuggestion && (
+
+ {
+ setShowSuggestion(false)
+ }}
+ />
+
+ )}
{sortedApiKeys.length > 0 ? (
sortedApiKeys.map((apiKey, i) => {
diff --git a/packages/web/pages/settings/emails/index.tsx b/packages/web/pages/settings/emails/index.tsx
index fae30528e..fee815935 100644
--- a/packages/web/pages/settings/emails/index.tsx
+++ b/packages/web/pages/settings/emails/index.tsx
@@ -22,6 +22,7 @@ import {
SettingsTableRow,
} from '../../../components/templates/settings/SettingsTable'
import { ConfirmationModal } from '../../../components/patterns/ConfirmationModal'
+import { SuggestionBox } from '../../../components/elements/SuggestionBox'
enum TextType {
EmailAddress,
@@ -121,6 +122,11 @@ export default function EmailsPage(): JSX.Element {
headerTitle="Address"
createTitle="Create a new email address"
createAction={createEmail}
+ suggestionInfo={{
+ text: 'Create an Omnivore email address and use it to subscribe to newsletters. The newsletters will be automatically added to your library.',
+ docs: 'https://docs.omnivore.app/using/inbox.html',
+ key: '--settings-emails-show-help',
+ }}
>
{sortedEmailAddresses.length > 0 ? (
sortedEmailAddresses.map((email, i) => {
diff --git a/packages/web/pages/settings/emails/recent.tsx b/packages/web/pages/settings/emails/recent.tsx
index 3dd1107b4..ce1dace90 100644
--- a/packages/web/pages/settings/emails/recent.tsx
+++ b/packages/web/pages/settings/emails/recent.tsx
@@ -168,9 +168,14 @@ export default function RecentEmails(): JSX.Element {
return (
{sortedRecentEmails.length > 0 ? (
sortedRecentEmails.map((recentEmail: RecentEmail, i) => {
diff --git a/packages/web/pages/settings/feeds/index.tsx b/packages/web/pages/settings/feeds/index.tsx
index cbe310e8c..7abae14d2 100644
--- a/packages/web/pages/settings/feeds/index.tsx
+++ b/packages/web/pages/settings/feeds/index.tsx
@@ -96,6 +96,11 @@ export default function Rss(): JSX.Element {
createAction={() => {
router.push('/settings/feeds/add')
}}
+ suggestionInfo={{
+ text: 'Add RSS and Atom feeds to your Omnivore account. When you add a new feed the last 24hrs of items, or at least one item will be added to your account.',
+ docs: 'https://docs.omnivore.app/using/feeds.html',
+ key: '--settings-feeds-show-help',
+ }}
>
{subscriptions.length === 0 ? (
diff --git a/packages/web/pages/settings/labels.tsx b/packages/web/pages/settings/labels.tsx
index 572002fc2..bfbd31665 100644
--- a/packages/web/pages/settings/labels.tsx
+++ b/packages/web/pages/settings/labels.tsx
@@ -35,6 +35,8 @@ import {
import { LabelChip } from '../../components/elements/LabelChip'
import { ConfirmationModal } from '../../components/patterns/ConfirmationModal'
import { InfoLink } from '../../components/elements/InfoLink'
+import { SuggestionBox } from '../../components/elements/SuggestionBox'
+import { usePersistedState } from '../../lib/hooks/usePersistedState'
const HeaderWrapper = styled(Box, {
width: '100%',
@@ -153,6 +155,10 @@ export default function LabelsPage(): JSX.Element {
const [confirmRemoveLabelId, setConfirmRemoveLabelId] = useState<
string | null
>(null)
+ const [showLabelPageHelp, setShowLabelPageHelp] = usePersistedState({
+ key: `--settings-labels-show-help`,
+ initialValue: true,
+ })
const breakpoint = 768
applyStoredTheme(false)
@@ -270,6 +276,21 @@ export default function LabelsPage(): JSX.Element {
onOpenChange={() => setConfirmRemoveLabelId(null)}
/>
) : null}
+ {showLabelPageHelp && (
+
+ {
+ setShowLabelPageHelp(false)
+ }}
+ />
+
+ )}
<>
{sortedSubscriptions.length > 0 ? (