From d13397d4dd234bf98f2804b9cc95a91719c780ca Mon Sep 17 00:00:00 2001 From: zeppi Date: Wed, 2 Feb 2022 01:19:39 -0500 Subject: [PATCH] new custom comment servers ux --- flow-typed/Settings.js | 8 ++ static/app-strings.json | 6 + ui/component/common/item-panel-input-row.jsx | 104 +++++++++++++++ ui/component/common/item-panel.jsx | 43 +++++++ ui/component/settingCommentsServer/index.js | 2 + ui/component/settingCommentsServer/view.jsx | 127 ++++++++++++------- ui/constants/settings.js | 1 + ui/redux/reducers/settings.js | 1 + ui/scss/all.scss | 1 + ui/scss/component/_form-field.scss | 7 +- ui/scss/component/_item-panel.scss | 42 ++++++ ui/scss/component/section.scss | 4 +- 12 files changed, 296 insertions(+), 50 deletions(-) create mode 100644 flow-typed/Settings.js create mode 100644 ui/component/common/item-panel-input-row.jsx create mode 100644 ui/component/common/item-panel.jsx create mode 100644 ui/scss/component/_item-panel.scss diff --git a/flow-typed/Settings.js b/flow-typed/Settings.js new file mode 100644 index 000000000..89fc59118 --- /dev/null +++ b/flow-typed/Settings.js @@ -0,0 +1,8 @@ +declare type CommentServerDetails = { + name: string, + url: string, +} + +declare type WalletServerDetails = { + +}; diff --git a/static/app-strings.json b/static/app-strings.json index 5da607612..9125daa73 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -2269,5 +2269,11 @@ "Automatic Hosting lets you delegate some amount of storage for the network to automatically download and host.": "Automatic Hosting lets you delegate some amount of storage for the network to automatically download and host.", "Help improve the P2P data network (and make LBRY happy) by hosting data.": "Help improve the P2P data network (and make LBRY happy) by hosting data.", "Limit Hosting of Content History": "Limit Hosting of Content History", + "Remove custom comment server": "Remove custom comment server", + "Use Https": "Use Https", + "Server URL": "Server URL", + "Use https": "Use https", + "Custom Servers": "Custom Servers", + "Add A Server": "Add A Server", "--end--": "--end--" } diff --git a/ui/component/common/item-panel-input-row.jsx b/ui/component/common/item-panel-input-row.jsx new file mode 100644 index 000000000..e561669e0 --- /dev/null +++ b/ui/component/common/item-panel-input-row.jsx @@ -0,0 +1,104 @@ +// @flow +import React, { useState, useEffect } from 'react'; +import Button from 'component/button'; +import { Form, FormField } from 'component/common/form'; + +type Props = { + update: (CommentServerDetails) => void, + onCancel: (boolean) => void, +}; + +const VALID_IPADDRESS_REGEX = new RegExp( + '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\.)){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' +); +const VALID_HOSTNAME_REGEX = new RegExp( + '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(\\.))+([A-Za-z]|[A-Za-z][A-Za-z]*[A-Za-z])$' +); + +const VALID_ENDPOINT_REGEX = new RegExp('^((\\/)([a-zA-Z0-9]+))+$'); + +const isValidServerString = (serverString) => { + const si = serverString.indexOf('/'); + const pi = serverString.indexOf(':'); + const path = si === -1 ? '' : serverString.slice(si); + console.log('path', path); + const hostMaybePort = si === -1 ? serverString : serverString.slice(0, si); + const host = pi === -1 ? hostMaybePort : hostMaybePort.slice(0, pi); + const port = pi === -1 ? '' : hostMaybePort.slice(pi + 1); + console.log('port', port); + const portInt = parseInt(port); + + return ( + (host === 'localhost' || VALID_IPADDRESS_REGEX.test(host) || VALID_HOSTNAME_REGEX.test(host)) && + (!path || VALID_ENDPOINT_REGEX.test(path)) && + // eslint-disable-next-line + (pi === -1 || (port && typeof portInt === 'number' && portInt === portInt)) + ); // NaN !== NaN +}; + +function ServerInputRow(props: Props) { + const { update, onCancel } = props; + const [nameString, setNameString] = useState(''); + const [hostString, setHostString] = useState(''); + const [useHttps, setUseHttps] = useState(true); + + const getHostString = () => { + return `${useHttps ? 'https://' : 'http://'}${hostString}`; + }; + + const [validServerString, setValidServerString] = useState(false); + + useEffect(() => { + setValidServerString(isValidServerString(hostString)); + }, [hostString, validServerString, setValidServerString]); + + function onSubmit() { + const updateValue = { url: getHostString(), name: nameString }; + update(updateValue); + setHostString(''); + setNameString(''); + } + + return ( +
+
+ setNameString(e.target.value)} + /> +
+
+ +
{`${useHttps ? 'https://' : 'http://'}`}
+
+ setHostString(e.target.value)} + name={'serverUrl'} + /> +
+
+
+ setUseHttps(!useHttps)} + /> +
+ +
+
+
+ ); +} + +export default ServerInputRow; diff --git a/ui/component/common/item-panel.jsx b/ui/component/common/item-panel.jsx new file mode 100644 index 000000000..b95caf60a --- /dev/null +++ b/ui/component/common/item-panel.jsx @@ -0,0 +1,43 @@ +// @flow +import React from 'react'; +import * as ICONS from 'constants/icons'; +import Button from 'component/button'; +import classnames from 'classnames'; + +type Props = { + onClick: (CommentServerDetails) => void, + onRemove?: (CommentServerDetails) => void, + active: boolean, + serverDetails: CommentServerDetails, +}; + +/* + [ https://myserver.com x ] + [ https://myserver.com x (selected)] + + [ https://myserver.com:50001 x (selected)] + */ + +const ItemPanel = (props: Props) => { + const { onClick, active, serverDetails, onRemove } = props; + + return ( +
onClick(serverDetails)} className={classnames('itemPanel', { 'itemPanel--active': active })}> +
+
{`${serverDetails.name}`}
+
{`${serverDetails.url}`}
+
+ {onRemove && ( +
)} - + {addServer && } + ); } diff --git a/ui/constants/settings.js b/ui/constants/settings.js index 72363de04..86d0b7e20 100644 --- a/ui/constants/settings.js +++ b/ui/constants/settings.js @@ -41,6 +41,7 @@ export const VIDEO_THEATER_MODE = 'video_theater_mode'; export const VIDEO_PLAYBACK_RATE = 'video_playback_rate'; export const CUSTOM_COMMENTS_SERVER_ENABLED = 'custom_comments_server_enabled'; export const CUSTOM_COMMENTS_SERVER_URL = 'custom_comments_server_url'; +export const CUSTOM_COMMENTS_SERVERS = 'custom_comments_servers'; export const CUSTOM_SHARE_URL_ENABLED = 'custom_share_url_enabled'; export const CUSTOM_SHARE_URL = 'custom_share_url'; export const ENABLE_PRERELEASE_UPDATES = 'enable_prerelease_updates'; diff --git a/ui/redux/reducers/settings.js b/ui/redux/reducers/settings.js index 4e013e35e..bbdd22c09 100644 --- a/ui/redux/reducers/settings.js +++ b/ui/redux/reducers/settings.js @@ -45,6 +45,7 @@ const defaultState = { [SETTINGS.DESKTOP_WINDOW_ZOOM]: 1, [SETTINGS.CUSTOM_COMMENTS_SERVER_ENABLED]: false, [SETTINGS.CUSTOM_COMMENTS_SERVER_URL]: '', + [SETTINGS.CUSTOM_COMMENTS_SERVERS]: [], [SETTINGS.CUSTOM_SHARE_URL_ENABLED]: false, [SETTINGS.CUSTOM_SHARE_URL]: '', diff --git a/ui/scss/all.scss b/ui/scss/all.scss index 8ecba7ad6..c68b9ab87 100644 --- a/ui/scss/all.scss +++ b/ui/scss/all.scss @@ -68,3 +68,4 @@ @import 'component/wallet-tip-send'; @import 'component/swipe-list'; @import 'component/utils'; +@import 'component/item-panel'; diff --git a/ui/scss/component/_form-field.scss b/ui/scss/component/_form-field.scss index 2d7a88c85..cddd06630 100644 --- a/ui/scss/component/_form-field.scss +++ b/ui/scss/component/_form-field.scss @@ -293,7 +293,9 @@ input[type='number'] { fieldset-group { + fieldset-group { - margin-top: var(--spacing-s); + &:not(.fieldset-group--row) { + margin-top: var(--spacing-s); + } } &.fieldset-group--smushed { @@ -339,6 +341,9 @@ fieldset-group { align-items: flex-end; justify-content: center; } + + &:not(.fieldset-group--row) { + } } // This is a special case where the prefix appears "inside" the input diff --git a/ui/scss/component/_item-panel.scss b/ui/scss/component/_item-panel.scss new file mode 100644 index 000000000..51c2bdace --- /dev/null +++ b/ui/scss/component/_item-panel.scss @@ -0,0 +1,42 @@ +.itemPanel { + padding: var(--spacing-m); + margin-bottom: var(--spacing-m); + width: 100%; + background-color: var(--color-card-background); + border-radius: var(--card-radius); + overflow: hidden; + border: 1px solid var(--color-border); + display: flex; + justify-content: space-between; + .button--close { + position: unset; + } + &:last-child { + margin-bottom: 0; + } +} + +.itemPanel__details { + display: flex; + flex-direction: row; + flex-wrap: wrap; + @media (max-width: $breakpoint-small) { + flex-direction: column; + } +} +.itemPanel__name { + min-width: 100px; + width: 100px; +} +.itemPanel__url { + text-overflow: ellipsis; +} + +.itemPanel--active { + color: var(--color-button-toggle-text); + background-color: var(--color-button-toggle-bg); +} + +.itemPanel--input { + padding: 0 0 var(--spacing-s) 0; +} diff --git a/ui/scss/component/section.scss b/ui/scss/component/section.scss index d66a716d0..56c4d12f9 100644 --- a/ui/scss/component/section.scss +++ b/ui/scss/component/section.scss @@ -250,7 +250,9 @@ } fieldset-group { - margin-top: var(--spacing-m); + &:not(.fieldset-group--row) { + margin-top: var(--spacing-m); + } } .tags__input-wrapper {