diff options
author | 2024-07-08 09:38:27 +0200 | |
---|---|---|
committer | 2024-07-08 09:38:27 +0200 | |
commit | bbbf6ebe376c7b6c3a64e14571a3a477b880e3ad (patch) | |
tree | d24aa92f743de5c440ce786d61cc86f72bf9a3e7 | |
parent | [chore]: Bump github.com/microcosm-cc/bluemonday from 1.0.26 to 1.0.27 (#3081) (diff) | |
download | gotosocial-bbbf6ebe376c7b6c3a64e14571a3a477b880e3ad.tar.xz |
[frontend] Better autocapitalize/spellcheck settings on forms (#3077)
20 files changed, 205 insertions, 38 deletions
diff --git a/web/source/settings/views/admin/actions/keys/expireremote.tsx b/web/source/settings/views/admin/actions/keys/expireremote.tsx index d695ec0c8..1d62f9439 100644 --- a/web/source/settings/views/admin/actions/keys/expireremote.tsx +++ b/web/source/settings/views/admin/actions/keys/expireremote.tsx @@ -22,9 +22,33 @@ import { TextInput } from "../../../../components/form/inputs"; import MutationButton from "../../../../components/form/mutation-button"; import { useTextInput } from "../../../../lib/form"; import { useInstanceKeysExpireMutation } from "../../../../lib/query/admin/actions"; +import isValidDomain from "is-valid-domain"; export default function ExpireRemote({}) { - const domainField = useTextInput("domain"); + const domainField = useTextInput("domain", { + validator: (v: string) => { + if (v.length === 0) { + return ""; + } + + if (v[v.length-1] === ".") { + return "invalid domain"; + } + + const valid = isValidDomain(v, { + subdomain: true, + wildcard: false, + allowUnicode: true, + topLevel: false, + }); + + if (valid) { + return ""; + } + + return "invalid domain"; + } + }); const [expire, expireResult] = useInstanceKeysExpireMutation(); @@ -52,11 +76,13 @@ export default function ExpireRemote({}) { <TextInput field={domainField} label="Domain" - type="string" + type="text" + autoCapitalize="none" + spellCheck="false" placeholder="example.org" /> <MutationButton - disabled={!domainField.value} + disabled={!domainField.value || !domainField.valid} label="Expire keys" result={expireResult} /> diff --git a/web/source/settings/views/admin/debug/apurl/index.tsx b/web/source/settings/views/admin/debug/apurl/index.tsx index a0c2fc738..b66794132 100644 --- a/web/source/settings/views/admin/debug/apurl/index.tsx +++ b/web/source/settings/views/admin/debug/apurl/index.tsx @@ -53,6 +53,9 @@ export default function ApURL() { <TextInput field={urlField} label="URL" + type="url" + pattern="(http|https):\/\/.+" + placeholder="https://example.org/users/someone" /> <MutationButton disabled={!urlField.value} diff --git a/web/source/settings/views/admin/emoji/category-select.tsx b/web/source/settings/views/admin/emoji/category-select.tsx index 683e146d8..fabcad9b6 100644 --- a/web/source/settings/views/admin/emoji/category-select.tsx +++ b/web/source/settings/views/admin/emoji/category-select.tsx @@ -126,6 +126,8 @@ export function CategorySelect({ field, children }: PropsWithChildren<CategorySe items={categoryItems} label="Category" placeholder="e.g., reactions" + autoCapitalize="none" + spellCheck="false" > {children} </ComboBox> diff --git a/web/source/settings/views/admin/emoji/local/new-emoji.tsx b/web/source/settings/views/admin/emoji/local/new-emoji.tsx index f2f5a56b1..b9c37ca8e 100644 --- a/web/source/settings/views/admin/emoji/local/new-emoji.tsx +++ b/web/source/settings/views/admin/emoji/local/new-emoji.tsx @@ -117,6 +117,8 @@ export default function NewEmojiForm() { <TextInput field={form.shortcode} label="Shortcode, must be unique among the instance's local emoji" + autoCapitalize="none" + spellCheck="false" {...{pattern: "^\\w{2,30}$"}} /> diff --git a/web/source/settings/views/admin/emoji/local/overview.tsx b/web/source/settings/views/admin/emoji/local/overview.tsx index b4fa48d74..e9c5fae0c 100644 --- a/web/source/settings/views/admin/emoji/local/overview.tsx +++ b/web/source/settings/views/admin/emoji/local/overview.tsx @@ -116,6 +116,8 @@ function EmojiList({ emoji }: EmojiListParams) { field={filterField} name="emoji-shortcode" placeholder="Search" + autoCapitalize="none" + spellCheck="false" /> </div> <div className="entries scrolling"> diff --git a/web/source/settings/views/admin/emoji/remote/steal-this-look.tsx b/web/source/settings/views/admin/emoji/remote/steal-this-look.tsx index 43d0b83e1..69d7b8bb5 100644 --- a/web/source/settings/views/admin/emoji/remote/steal-this-look.tsx +++ b/web/source/settings/views/admin/emoji/remote/steal-this-look.tsx @@ -52,9 +52,10 @@ export default function StealThisLook({ emojiCodes }) { </label> <div className="row"> <input - type="text" id="url" name="url" + type="url" + pattern="(http|https):\/\/.+" onChange={urlField.onChange} value={urlField.value} /> diff --git a/web/source/settings/views/admin/http-header-permissions/create.tsx b/web/source/settings/views/admin/http-header-permissions/create.tsx index 6613ac0f1..b3fec4b6d 100644 --- a/web/source/settings/views/admin/http-header-permissions/create.tsx +++ b/web/source/settings/views/admin/http-header-permissions/create.tsx @@ -100,7 +100,7 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType field={form.header} label={ <> - HTTP Header Name + Header Name <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" target="_blank" @@ -112,12 +112,15 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType </> } placeholder={"User-Agent"} + autoCapitalize="none" + spellCheck="false" + {...{className: "monospace"}} /> <TextInput field={form.regex} label={ <> - HTTP Header Value RE2 Regex + Value Regex <a href="https://github.com/google/re2/wiki/Syntax" target="_blank" @@ -129,6 +132,8 @@ export default function HeaderPermCreateForm({ permType }: { permType: PermType </> } placeholder={"^.*Some-User-Agent.*$"} + autoCapitalize="none" + spellCheck="false" {...{className: "monospace"}} /> <MutationButton diff --git a/web/source/settings/views/admin/http-header-permissions/detail.tsx b/web/source/settings/views/admin/http-header-permissions/detail.tsx index 456f9a357..522f2dba2 100644 --- a/web/source/settings/views/admin/http-header-permissions/detail.tsx +++ b/web/source/settings/views/admin/http-header-permissions/detail.tsx @@ -164,7 +164,7 @@ function PermDeets({ <dl className="info-list"> <div className="info-list-entry"> <dt>ID</dt> - <dd>{perm.id}</dd> + <dd className="monospace">{perm.id}</dd> </div> <div className="info-list-entry"> <dt>Created</dt> @@ -176,10 +176,10 @@ function PermDeets({ </div> <div className="info-list-entry"> <dt>Header Name</dt> - <dd>{perm.header}</dd> + <dd className="monospace">{perm.header}</dd> </div> <div className="info-list-entry"> - <dt>Header Value Regex</dt> + <dt>Value Regex</dt> <dd className="monospace">{perm.regex}</dd> </div> <div className="info-list-entry"> diff --git a/web/source/settings/views/admin/instance/settings.tsx b/web/source/settings/views/admin/instance/settings.tsx index 03a961589..8d377a6ea 100644 --- a/web/source/settings/views/admin/instance/settings.tsx +++ b/web/source/settings/views/admin/instance/settings.tsx @@ -79,7 +79,10 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) { const [submitForm, result] = useFormSubmit(form, useUpdateInstanceMutation()); return ( - <form onSubmit={submitForm}> + <form + onSubmit={submitForm} + autoComplete="none" + > <h1>Instance Settings</h1> <div className="form-section-docs"> @@ -97,7 +100,8 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) { <TextInput field={form.title} label={`Instance title (max ${titleLimit} characters)`} - placeholder="My GoToSocial instance" + autoCapitalize="words" + placeholder="My GoToSocial Instance" /> <div className="file-upload" aria-labelledby="avatar"> @@ -117,6 +121,7 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) { field={form.thumbnailDesc} label="Avatar image description" placeholder="A cute drawing of a smiling sloth." + autoCapitalize="sentences" /> </div> </div> @@ -139,6 +144,7 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) { field={form.shortDesc} label={`Short description (markdown accepted, max ${shortDescLimit} characters)`} placeholder="A small testing instance for the GoToSocial alpha software." + autoCapitalize="sentences" rows={6} /> @@ -146,6 +152,7 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) { field={form.description} label={`Full description (markdown accepted, max ${descLimit} characters)`} placeholder="A small testing instance for the GoToSocial alpha software. Just trying it out, my main instance is https://example.com" + autoCapitalize="sentences" rows={6} /> @@ -153,6 +160,7 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) { field={form.terms} label={`Terms & Conditions (markdown accepted, max ${termsLimit} characters)`} placeholder="Terms and conditions of using this instance, data policy, imprint, GDPR stuff, yadda yadda." + autoCapitalize="sentences" rows={6} /> @@ -172,12 +180,15 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) { field={form.contactUser} label="Contact user (local account username)" placeholder="admin" + autoCapitalize="none" + spellCheck="false" /> <TextInput field={form.contactEmail} label="Contact email" placeholder="admin@example.com" + type="email" /> <MutationButton label="Save" result={result} disabled={false} /> diff --git a/web/source/settings/views/moderation/accounts/detail/actions.tsx b/web/source/settings/views/moderation/accounts/detail/actions.tsx index 4132b778a..ddcb1a5de 100644 --- a/web/source/settings/views/moderation/accounts/detail/actions.tsx +++ b/web/source/settings/views/moderation/accounts/detail/actions.tsx @@ -78,14 +78,21 @@ function ModerateAccount({ account }: { account: AdminAccount }) { > <h3 id="account-moderation-actions">Account Moderation Actions</h3> <div> - Currently only the "suspend" action is implemented.<br/> - Suspending an account will delete it from your server, and remove all of its media, posts, relationships, etc.<br/> - If the suspended account is local, suspending will also send out a "delete" message to other servers, requesting them to remove its data from their instance as well.<br/> + Currently only the "suspend" action is implemented. + <br/> + Suspending an account will delete it from your server, + and remove all of its media, posts, relationships, etc. + <br/> + If the suspended account is local, suspending will also + send out a "delete" message to other servers, requesting + them to remove its data from their instance as well. + <br/> <b>Account suspension cannot be reversed.</b> </div> <TextInput field={form.reason} placeholder="Reason for this action" + autoCapitalize="sentences" /> <div className="action-buttons"> <MutationButton diff --git a/web/source/settings/views/moderation/accounts/index.tsx b/web/source/settings/views/moderation/accounts/index.tsx index 946ed323d..8464c8489 100644 --- a/web/source/settings/views/moderation/accounts/index.tsx +++ b/web/source/settings/views/moderation/accounts/index.tsx @@ -23,12 +23,16 @@ import { AccountSearchForm } from "./search"; export default function AccountsSearch({ }) { return ( <div className="accounts-view"> - <h1>Accounts Search</h1> - <span> - You can perform actions on an account by clicking - its name in a report, or by searching for the account - using the form below and clicking on its name. - </span> + <div className="form-section-docs"> + <h1>Accounts Search</h1> + <p> + You can perform actions on an account by clicking + its name in a report, or by searching for the account + using the form below and clicking on its name. + <br/> + All fields in the below form are optional. + </p> + </div> <AccountSearchForm /> </div> ); diff --git a/web/source/settings/views/moderation/accounts/pending/index.tsx b/web/source/settings/views/moderation/accounts/pending/index.tsx index d47363954..f03c4800c 100644 --- a/web/source/settings/views/moderation/accounts/pending/index.tsx +++ b/web/source/settings/views/moderation/accounts/pending/index.tsx @@ -44,7 +44,23 @@ export default function AccountsPending() { return ( <div className="accounts-view"> - <h1>Pending Accounts</h1> + <div className="form-section-docs"> + <h1>Pending Accounts</h1> + <p> + You can see a list of pending account sign-ups below. + <br/> + To approve or reject a sign-up, click on the account's name in the + list, and use the controls at the bottom of the account detail view. + </p> + <a + href="https://docs.gotosocial.org/en/latest/admin/signups/" + target="_blank" + className="docslink" + rel="noreferrer" + > + Learn more about account sign-ups (opens in a new tab) + </a> + </div> <PageableList isLoading={searchRes.isLoading} isFetching={searchRes.isFetching} diff --git a/web/source/settings/views/moderation/accounts/search/index.tsx b/web/source/settings/views/moderation/accounts/search/index.tsx index f37e22a66..504746adc 100644 --- a/web/source/settings/views/moderation/accounts/search/index.tsx +++ b/web/source/settings/views/moderation/accounts/search/index.tsx @@ -27,6 +27,7 @@ import MutationButton from "../../../../components/form/mutation-button"; import { useLocation, useSearch } from "wouter"; import { AdminAccount } from "../../../../lib/types/account"; import Username from "../../../../components/username"; +import isValidDomain from "is-valid-domain"; export function AccountSearchForm() { const [ location, setLocation ] = useLocation(); @@ -42,7 +43,31 @@ export function AccountSearchForm() { permissions: useTextInput("permissions", { defaultValue: urlQueryParams.get("permissions") ?? ""}), username: useTextInput("username", { defaultValue: urlQueryParams.get("username") ?? ""}), display_name: useTextInput("display_name", { defaultValue: urlQueryParams.get("display_name") ?? ""}), - by_domain: useTextInput("by_domain", { defaultValue: urlQueryParams.get("by_domain") ?? ""}), + by_domain: useTextInput("by_domain", { + defaultValue: urlQueryParams.get("by_domain") ?? "", + validator: (v: string) => { + if (v.length === 0) { + return ""; + } + + if (v[v.length-1] === ".") { + return "invalid domain"; + } + + const valid = isValidDomain(v, { + subdomain: true, + wildcard: false, + allowUnicode: true, + topLevel: false, + }); + + if (valid) { + return ""; + } + + return "invalid domain"; + } + }), email: useTextInput("email", { defaultValue: urlQueryParams.get("email") ?? ""}), ip: useTextInput("ip", { defaultValue: urlQueryParams.get("ip") ?? ""}), limit: useTextInput("limit", { defaultValue: urlQueryParams.get("limit") ?? "50"}) @@ -109,13 +134,17 @@ export function AccountSearchForm() { > <TextInput field={form.username} - label={"(Optional) username (without leading '@' symbol)"} + label={`Username (without "@" prefix) - case sensitive`} placeholder="someone" + autoCapitalize="none" + spellCheck="false" /> <TextInput field={form.by_domain} - label={"(Optional) domain"} + label={`Domain (without "https://" prefix)`} placeholder="example.org" + autoCapitalize="none" + spellCheck="false" /> <Select field={form.origin} @@ -130,15 +159,18 @@ export function AccountSearchForm() { ></Select> <TextInput field={form.email} - label={"(Optional) email address (local accounts only)"} + label={"Email address (local accounts only)"} placeholder={"someone@example.org"} // Get email validation for free. - {...{type: "email"}} + type="email" /> <TextInput field={form.ip} - label={"(Optional) IP address (local accounts only)"} + label={"IP address (local accounts only)"} placeholder={"198.51.100.0"} + autoCapitalize="none" + spellCheck="false" + className="monospace" /> <Select field={form.status} diff --git a/web/source/settings/views/moderation/domain-permissions/detail.tsx b/web/source/settings/views/moderation/domain-permissions/detail.tsx index 47072b8cb..2b27b534d 100644 --- a/web/source/settings/views/moderation/domain-permissions/detail.tsx +++ b/web/source/settings/views/moderation/domain-permissions/detail.tsx @@ -39,6 +39,7 @@ import { NoArg } from "../../../lib/types/query"; import { Error } from "../../../components/error"; import { useBaseUrl } from "../../../lib/navigation/util"; import { PermType } from "../../../lib/types/perm"; +import isValidDomain from "is-valid-domain"; export default function DomainPermDetail() { const baseUrl = useBaseUrl(); @@ -139,7 +140,32 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps) }; const form = { - domain: useTextInput("domain", { source: perm, defaultValue: defaultDomain }), + domain: useTextInput("domain", { + source: perm, + defaultValue: defaultDomain, + validator: (v: string) => { + if (v.length === 0) { + return ""; + } + + if (v[v.length-1] === ".") { + return "invalid domain"; + } + + const valid = isValidDomain(v, { + subdomain: true, + wildcard: false, + allowUnicode: true, + topLevel: false, + }); + + if (valid) { + return ""; + } + + return "invalid domain"; + } + }), obfuscate: useBoolInput("obfuscate", { source: perm }), commentPrivate: useTextInput("private_comment", { source: perm }), commentPublic: useTextInput("public_comment", { source: perm }) @@ -208,6 +234,8 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps) field={form.domain} label="Domain" placeholder="example.com" + autoCapitalize="none" + spellCheck="false" {...disabledForm} /> @@ -220,6 +248,7 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps) <TextArea field={form.commentPrivate} label="Private comment" + autoCapitalize="sentences" rows={3} {...disabledForm} /> @@ -227,6 +256,7 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps) <TextArea field={form.commentPublic} label="Public comment" + autoCapitalize="sentences" rows={3} {...disabledForm} /> diff --git a/web/source/settings/views/moderation/domain-permissions/form.tsx b/web/source/settings/views/moderation/domain-permissions/form.tsx index ea7fdbc23..204e9510c 100644 --- a/web/source/settings/views/moderation/domain-permissions/form.tsx +++ b/web/source/settings/views/moderation/domain-permissions/form.tsx @@ -80,9 +80,12 @@ export default function ImportExportForm({ form, submitParse, parseResult }: Imp <div className="import-export"> <TextArea field={form.domains} - label="Domains" + label="Domains (newline-separated)" placeholder={`google.com\nfacebook.com`} rows={8} + autoCapitalize="none" + spellCheck="false" + className={"monospace"} /> <RadioGroup diff --git a/web/source/settings/views/moderation/domain-permissions/overview.tsx b/web/source/settings/views/moderation/domain-permissions/overview.tsx index 1c919c14d..78560ba34 100644 --- a/web/source/settings/views/moderation/domain-permissions/overview.tsx +++ b/web/source/settings/views/moderation/domain-permissions/overview.tsx @@ -66,9 +66,11 @@ export default function DomainPermissionsOverview() { } return ( - <> - <h1>Domain {permTypeUpper}s</h1> - { permType == "block" ? <BlockHelperText/> : <AllowHelperText/> } + <div className={`domain-${permType}`}> + <div className="form-section-docs"> + <h1>Domain {permTypeUpper}s</h1> + { permType == "block" ? <BlockHelperText/> : <AllowHelperText/> } + </div> <DomainPermsList data={data} permType={permType} @@ -77,7 +79,7 @@ export default function DomainPermissionsOverview() { <Link to={`~${baseUrl}/import-export`}> Or use the bulk import/export interface </Link> - </> + </div> ); } diff --git a/web/source/settings/views/moderation/reports/detail.tsx b/web/source/settings/views/moderation/reports/detail.tsx index 7d6e542fb..298b5bd37 100644 --- a/web/source/settings/views/moderation/reports/detail.tsx +++ b/web/source/settings/views/moderation/reports/detail.tsx @@ -213,14 +213,18 @@ function ReportActionForm({ report }) { This is useful for providing an explanation about what action was taken (if any) before the report was marked as resolved. <br /> - <b> - Any comment made here will be visible - to the user that created the report! - </b> + <div className="info"> + <i className="fa fa-fw fa-exclamation-triangle" aria-hidden="true"></i> + <b> + If the report was created by a local account, then any + comment made here will be emailed to that account's user! + </b> + </div> </> <TextArea field={form.comment} label="Comment" + autoCapitalize="sentences" /> <MutationButton disabled={false} diff --git a/web/source/settings/views/user/migration.tsx b/web/source/settings/views/user/migration.tsx index 69aae6059..5c964d457 100644 --- a/web/source/settings/views/user/migration.tsx +++ b/web/source/settings/views/user/migration.tsx @@ -135,6 +135,8 @@ function AlsoKnownAsURI({ index, data }) { label={`Alias #${index+1}`} field={form.alsoKnownAsURI} placeholder={`https://example.org/users/my_other_account_${index+1}`} + type="url" + pattern="(http|https):\/\/.+" /> ); } @@ -190,10 +192,13 @@ function MoveForm({ data: profile }) { field={form.movedToURI} label="Move target URI" placeholder="https://example.org/users/my_new_account" + type="url" + pattern="(http|https):\/\/.+" /> <TextInput disabled={false} type="password" + autoComplete="current-password" name="password" field={form.password} label="Current account password" diff --git a/web/source/settings/views/user/profile.tsx b/web/source/settings/views/user/profile.tsx index a65405faa..17827ce9e 100644 --- a/web/source/settings/views/user/profile.tsx +++ b/web/source/settings/views/user/profile.tsx @@ -175,12 +175,15 @@ function UserProfileForm({ data: profile }) { <TextInput field={form.displayName} label="Display name" - placeholder="A GoToSocial user" + placeholder="A GoToSocial User" + autoCapitalize="words" + spellCheck="false" /> <TextArea field={form.note} label="Bio" placeholder="Just trying out GoToSocial, my pronouns are they/them and I like sloths." + autoCapitalize="sentences" rows={8} /> <b>Profile fields</b> @@ -233,6 +236,8 @@ function UserProfileForm({ data: profile }) { className="monospace" rows={8} disabled={!instanceConfig.allowCustomCSS} + autoCapitalize="none" + spellCheck="false" /> <MutationButton disabled={false} @@ -270,10 +275,14 @@ function Field({ index, data }) { <TextInput field={form.name} placeholder="Name" + autoCapitalize="none" + spellCheck="false" /> <TextInput field={form.value} placeholder="Value" + autoCapitalize="none" + spellCheck="false" /> </div> ); diff --git a/web/template/sign-up.tmpl b/web/template/sign-up.tmpl index 556486bf3..43513af62 100644 --- a/web/template/sign-up.tmpl +++ b/web/template/sign-up.tmpl @@ -58,6 +58,8 @@ required placeholder="Please enter your desired username" pattern="^[a-z0-9_]{1,64}$" + autocapitalize="off" + spellcheck="false" title="lowercase a-z, numbers, and underscores; max 64 characters" > </div> @@ -75,6 +77,7 @@ rows="8" minlength="40" maxlength="500" + autocapitalize="sentences" title="40-500 characters" ></textarea> </div> |