diff --git a/ui/public/manifest.json b/ui/public/manifest.json index f7d8555be..6f3e25798 100755 --- a/ui/public/manifest.json +++ b/ui/public/manifest.json @@ -13,6 +13,14 @@ "type": "image/png" } ], + "share_target": { + "action": "/unread/add", + "params": { + "title": "title", + "text": "text", + "url": "url" + } + }, "start_url": ".", "display": "standalone", "theme_color": "#000000", diff --git a/ui/src/articles/AddArticlePage.tsx b/ui/src/articles/AddArticlePage.tsx new file mode 100644 index 000000000..dedeb1891 --- /dev/null +++ b/ui/src/articles/AddArticlePage.tsx @@ -0,0 +1,43 @@ +import React from 'react' +import { RouteComponentProps } from 'react-router-dom' + +import Page from '../common/Page' +import { URLRegExp } from '../common/helpers' +import ButtonIcon from '../common/ButtonIcon' +import AddArticleForm from './components/AddArticleForm' + +type AllProps = RouteComponentProps + +export default ({ location, history }: AllProps) => { + const params = new URLSearchParams(location.search) + + let value = "" + if (params.has('url')) { + value = params.get('url')! + } else if (params.has('text') || params.has('title')) { + const text = params.get('text') || params.get('title')! + if (URLRegExp.test(text)) { + value = text + } else { + const matches = text.match(/\bhttps?:\/\/\S+/gi) + if (matches && URLRegExp.test(matches[0])) { + value = matches[0] + } + } + } + + const redirect = () => history.replace("/unread") + + return ( + + }> + + + ) +} diff --git a/ui/src/articles/Routes.tsx b/ui/src/articles/Routes.tsx index b12223184..caccd4878 100644 --- a/ui/src/articles/Routes.tsx +++ b/ui/src/articles/Routes.tsx @@ -1,10 +1,11 @@ import React from 'react' import { RouteComponentProps, Route, Switch } from 'react-router-dom' +import { ConnectedReduxProps } from '../store' + import ArticlesPage from './ArticlesPage' import ArticlePage from './ArticlePage' - -import { ConnectedReduxProps } from '../store' +import AddArticlePage from './AddArticlePage' // Combine both state + dispatch props - as well as any props we want to pass - in a union type. type AllProps = RouteComponentProps<{}> & ConnectedReduxProps @@ -12,6 +13,7 @@ type AllProps = RouteComponentProps<{}> & ConnectedReduxProps export default ({match}: AllProps) => ( + ) diff --git a/ui/src/articles/components/AddArticleForm.tsx b/ui/src/articles/components/AddArticleForm.tsx index ea427d9f1..cdf1ff690 100644 --- a/ui/src/articles/components/AddArticleForm.tsx +++ b/ui/src/articles/components/AddArticleForm.tsx @@ -18,6 +18,7 @@ interface AddArticleFormFields { } type Props = { + value?: string category?: Category onSuccess: (article: Article) => void onCancel: (e: any) => void @@ -25,10 +26,10 @@ type Props = { type AllProps = Props -export default ({ category, onSuccess, onCancel }: AllProps) => { +export default ({ value, category, onSuccess, onCancel }: AllProps) => { const [loading, setLoading] = useState(false) const [errorMessage, setErrorMessage] = useState(null) - const [formState, { url }] = useFormState() + const [formState, { url }] = useFormState({url: value}) const addArticleMutation = useMutation(AddNewArticle) const addArticle = async (form: AddArticleFormFields) => { diff --git a/ui/src/common/helpers.tsx b/ui/src/common/helpers.tsx index 21197a870..ce538b64c 100644 --- a/ui/src/common/helpers.tsx +++ b/ui/src/common/helpers.tsx @@ -3,6 +3,14 @@ import { ApolloError } from "apollo-boost" import { FormState } from "react-use-form-state" import { API_BASE_URL } from "../constants"; + +export const URLRegExp = new RegExp('^(https?:\\/\\/)?'+ // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|'+ // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string + '(\\#[-a-z\\d_]*)?$','i') // fragment locator + export interface GQLResponsePattern { Loading: () => ReactNode Error: (err: ApolloError | Error) => ReactNode