diff options
| author | 2024-01-05 13:39:31 +0100 | |
|---|---|---|
| committer | 2024-01-05 13:39:31 +0100 | |
| commit | d5e3996a18ee37fc4bdf5718632d3d19ac7a8c1b (patch) | |
| tree | 7b8df224893611c77cadc847c2fd8d7ec239b636 /web/source | |
| parent | [bugfix] fix check for closed poll to account for non-zero closed time but in... (diff) | |
| download | gotosocial-d5e3996a18ee37fc4bdf5718632d3d19ac7a8c1b.tar.xz | |
[feature] Parse instance descriptors as markdown, show T&C on /about (#2481)
* [feature] Parse instance descriptors as markdown, show T&C on /about
* lint
* remove unnecessary nullzero tags
Diffstat (limited to 'web/source')
| -rw-r--r-- | web/source/css/about.css | 8 | ||||
| -rw-r--r-- | web/source/css/base.css | 76 | ||||
| -rw-r--r-- | web/source/css/status.css | 63 | ||||
| -rw-r--r-- | web/source/settings/admin/settings/index.jsx | 126 | ||||
| -rw-r--r-- | web/source/settings/admin/settings/index.tsx | 191 | ||||
| -rw-r--r-- | web/source/settings/index.js | 4 | ||||
| -rw-r--r-- | web/source/settings/lib/types/instance.ts | 40 | 
7 files changed, 294 insertions, 214 deletions
diff --git a/web/source/css/about.css b/web/source/css/about.css index 55318572c..0a2ac763f 100644 --- a/web/source/css/about.css +++ b/web/source/css/about.css @@ -27,12 +27,8 @@  	border: $boxshadow-border;  	border-radius: $br; -	.about-section { -		ul, ol { -			margin-top: 0; -		} -	 -		h3, h4 { +	.about-section {	 +		h1, h2, h3, h4, h5 {  			margin-top: 0;  		}  	} diff --git a/web/source/css/base.css b/web/source/css/base.css index 0d3c436c8..5198ce6b8 100644 --- a/web/source/css/base.css +++ b/web/source/css/base.css @@ -16,7 +16,12 @@  	along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ +/*************************************** +***** SECTION 0: IMPORTS AND FONTS ***** +****************************************/ +  @import "modern-normalize/modern-normalize.css"; +@import "./prism.css";  /* noto-sans-regular - latin */  @font-face { @@ -261,6 +266,77 @@ label {  	cursor: pointer;  } +/* +	Set our own nice background for +	monospace code and pre blocks. +*/ +pre, pre[class*="language-"], +code, code[class*="language-"] { +	background-color: $gray2; +} + +/* +	Just code on its own inside status +	content, ie, `here is some code`. +*/ +code { +	padding: 0.25rem; +	border-radius: $br-inner; +	white-space: pre-wrap; +} + +/* +	Restyle Prism code highlighting toolbar +	plugin buttons to our own button style. +	 +	We have to use really specific selectors +	because of how specific prism.css is. +*/ +div.code-toolbar > div.toolbar { +	margin-right: 0.5rem; +	display: flex; +	gap: 0.25rem; + +	> div.toolbar-item { +		> span, > button { +			color: $button-fg; +			background: $button-bg; +			font-weight: bold; +			box-shadow: $boxshadow; + +			&:hover, &:focus { +				color: $button-fg; +			} +		} + +		.copy-to-clipboard-button:hover { +			background: $button-hover-bg; +		} +	} +} + +pre, pre[class*="language-"] { +	border-radius: $br; +	padding: 0.5rem; +	white-space: pre; +	overflow-x: auto; + +	/*  +		Code inside a pre block, ie., +		 +		``` +		here is some code +		``` +	*/ +	code { +		width: 100%; +		padding: 0; +		white-space: pre; +		overflow-x: auto; +		-webkit-overflow-scrolling: touch; +	} +} +  /*************************************  ***** SECTION 3: UTILITY CLASSES *****  **************************************/ diff --git a/web/source/css/status.css b/web/source/css/status.css index 019fbd0b4..009dd9f2b 100644 --- a/web/source/css/status.css +++ b/web/source/css/status.css @@ -19,7 +19,6 @@  @import "photoswipe/dist/photoswipe.css";  @import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css";  @import "plyr/dist/plyr.css"; -@import "./prism.css";  main {  	background: transparent; @@ -194,68 +193,6 @@ main {  				line-height: initial;  			} -			pre, code { -				background-color: $gray2; -			} - -			/* -				Just code on its own inside status -				content, ie, `here is some code`. -			*/ -			code { -				padding: 0.25rem; -				border-radius: $br-inner; -				white-space: pre-wrap; -			} - -			/* -				Restyle Prism code highlighting toolbar -				plugin buttons to our own button style.  -			*/ -			.code-toolbar .toolbar { -				margin-right: 0.5rem; -				display: flex; -				gap: 0.25rem; - -				.toolbar-item { -					span, button { -						color: $button-fg; -						background: $button-bg; -						font-weight: bold; -					} - -					.copy-to-clipboard-button, span { -						box-shadow: $boxshadow; -					} - -					.copy-to-clipboard-button:hover, .copy-to-clipboard-button:hover span { -						background: $button-hover-bg; -					} -				} -			} - -			pre, pre[class*="language-"] { -				border-radius: $br; -				padding: 0.5rem; -				white-space: pre; -				overflow-x: auto; - -				/*  -					Code inside a pre block, ie., -					 -					``` -					here is some code -					``` -				*/ -				code { -					width: 100%; -					padding: 0; -					white-space: pre; -					overflow-x: auto; -					-webkit-overflow-scrolling: touch; -				} -			} -  			img {  				max-width: 100%;  				margin: 5px auto; diff --git a/web/source/settings/admin/settings/index.jsx b/web/source/settings/admin/settings/index.jsx deleted file mode 100644 index c0da83a2a..000000000 --- a/web/source/settings/admin/settings/index.jsx +++ /dev/null @@ -1,126 +0,0 @@ -/* -	GoToSocial -	Copyright (C) GoToSocial Authors admin@gotosocial.org -	SPDX-License-Identifier: AGPL-3.0-or-later - -	This program is free software: you can redistribute it and/or modify -	it under the terms of the GNU Affero General Public License as published by -	the Free Software Foundation, either version 3 of the License, or -	(at your option) any later version. - -	This program is distributed in the hope that it will be useful, -	but WITHOUT ANY WARRANTY; without even the implied warranty of -	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -	GNU Affero General Public License for more details. - -	You should have received a copy of the GNU Affero General Public License -	along with this program.  If not, see <http://www.gnu.org/licenses/>. -*/ - -const React = require("react"); - -const { -	useTextInput, -	useFileInput -} = require("../../lib/form"); - -const useFormSubmit = require("../../lib/form/submit").default; - -const { -	TextInput, -	TextArea, -	FileInput -} = require("../../components/form/inputs"); - -const FormWithData = require("../../lib/form/form-with-data").default; -const MutationButton = require("../../components/form/mutation-button"); - -const { useInstanceV1Query } = require("../../lib/query"); -const { useUpdateInstanceMutation } = require("../../lib/query/admin"); - -module.exports = function AdminSettings() { -	return ( -		<FormWithData -			dataQuery={useInstanceV1Query} -			DataForm={AdminSettingsForm} -		/> -	); -}; - -function AdminSettingsForm({ data: instance }) { -	const form = { -		title: useTextInput("title", { -			source: instance, -			validator: (val) => val.length <= 40 ? "" : "Instance title must be 40 characters or less" -		}), -		thumbnail: useFileInput("thumbnail", { withPreview: true }), -		thumbnailDesc: useTextInput("thumbnail_description", { source: instance }), -		shortDesc: useTextInput("short_description", { source: instance }), -		description: useTextInput("description", { source: instance }), -		contactUser: useTextInput("contact_username", { source: instance, valueSelector: (s) => s.contact_account?.username }), -		contactEmail: useTextInput("contact_email", { source: instance, valueSelector: (s) => s.email }), -		terms: useTextInput("terms", { source: instance }) -	}; - -	const [submitForm, result] = useFormSubmit(form, useUpdateInstanceMutation()); - -	return ( -		<form onSubmit={submitForm}> -			<h1>Instance Settings</h1> -			<TextInput -				field={form.title} -				label="Title" -				placeholder="My GoToSocial instance" -			/> - -			<div className="file-upload"> -				<h3>Instance thumbnail</h3> -				<div> -					<img className="preview avatar" src={form.thumbnail.previewValue ?? instance.thumbnail} alt={form.thumbnailDesc.value ?? (instance.thumbnail ? `Thumbnail image for the instance` : "No instance thumbnail image set")} /> -					<FileInput -						field={form.thumbnail} -						accept="image/*" -					/> -				</div> -			</div> - -			<TextInput -				field={form.thumbnailDesc} -				label="Instance thumbnail description" -				placeholder="A cute drawing of a smiling sloth." -			/> - -			<TextArea -				field={form.shortDesc} -				label="Short description" -				placeholder="A small testing instance for the GoToSocial alpha software." -			/> - -			<TextArea -				field={form.description} -				label="Full description" -				placeholder="A small testing instance for the GoToSocial alpha software. Just trying it out, my main instance is https://example.com" -			/> - -			<TextInput -				field={form.contactUser} -				label="Contact user (local account username)" -				placeholder="admin" -			/> - -			<TextInput -				field={form.contactEmail} -				label="Contact email" -				placeholder="admin@example.com" -			/> - -			<TextArea -				field={form.terms} -				label="Terms & Conditions" -				placeholder="" -			/> - -			<MutationButton label="Save" result={result} /> -		</form> -	); -}
\ No newline at end of file diff --git a/web/source/settings/admin/settings/index.tsx b/web/source/settings/admin/settings/index.tsx new file mode 100644 index 000000000..4e5ea343a --- /dev/null +++ b/web/source/settings/admin/settings/index.tsx @@ -0,0 +1,191 @@ +/* +	GoToSocial +	Copyright (C) GoToSocial Authors admin@gotosocial.org +	SPDX-License-Identifier: AGPL-3.0-or-later + +	This program is free software: you can redistribute it and/or modify +	it under the terms of the GNU Affero General Public License as published by +	the Free Software Foundation, either version 3 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU Affero General Public License for more details. + +	You should have received a copy of the GNU Affero General Public License +	along with this program.  If not, see <http://www.gnu.org/licenses/>. +*/ + +import React from "react"; + +import { useTextInput, useFileInput } from "../../lib/form"; + +const useFormSubmit = require("../../lib/form/submit").default; + +import { TextInput, TextArea, FileInput } from "../../components/form/inputs"; + +const FormWithData = require("../../lib/form/form-with-data").default; +import MutationButton from "../../components/form/mutation-button"; + +import { useInstanceV1Query } from "../../lib/query"; +import { useUpdateInstanceMutation } from "../../lib/query/admin"; +import { InstanceV1 } from "../../lib/types/instance"; + +export default function AdminSettings() { +	return ( +		<FormWithData +			dataQuery={useInstanceV1Query} +			DataForm={AdminSettingsForm} +		/> +	); +} + +interface AdminSettingsFormProps{ +	data: InstanceV1; +} + +function AdminSettingsForm({ data: instance }: AdminSettingsFormProps) { +	const titleLimit = 40; +	const shortDescLimit = 500; +	const descLimit = 5000; +	const termsLimit = 5000; +	 +	const form = { +		title: useTextInput("title", { +			source: instance, +			validator: (val: string) => val.length <= titleLimit ? "" : `Instance title is ${val.length} characters; must be ${titleLimit} characters or less` +		}), +		thumbnail: useFileInput("thumbnail", { withPreview: true }), +		thumbnailDesc: useTextInput("thumbnail_description", { source: instance }), +		shortDesc: useTextInput("short_description", { +			source: instance, +			// Select "raw" text version of parsed field for editing. +			valueSelector: (s: InstanceV1) => s.short_description_text, +			validator: (val: string) => val.length <= shortDescLimit ? "" : `Instance short description is ${val.length} characters; must be ${shortDescLimit} characters or less` +		}), +		description: useTextInput("description", { +			source: instance, +			// Select "raw" text version of parsed field for editing. +			valueSelector: (s: InstanceV1) => s.description_text, +			validator: (val: string) => val.length <= descLimit ? "" : `Instance description is ${val.length} characters; must be ${descLimit} characters or less` +		}), +		terms: useTextInput("terms", { +			source: instance, +			// Select "raw" text version of parsed field for editing. +			valueSelector: (s: InstanceV1) => s.terms_text, +			validator: (val: string) => val.length <= termsLimit ? "" : `Instance terms and conditions is ${val.length} characters; must be ${termsLimit} characters or less` +		}), +		contactUser: useTextInput("contact_username", { source: instance, valueSelector: (s) => s.contact_account?.username }), +		contactEmail: useTextInput("contact_email", { source: instance, valueSelector: (s) => s.email }) +	}; + +	const [submitForm, result] = useFormSubmit(form, useUpdateInstanceMutation()); + +	return ( +		<form onSubmit={submitForm}> +			<h1>Instance Settings</h1> + +			<div className="form-section-docs"> +				<h3>Appearance</h3> +				<a +					href="https://docs.gotosocial.org/en/latest/admin/settings/#instance-appearance" +					target="_blank" +					className="docslink" +					rel="noreferrer" +				> +					Learn more about these settings (opens in a new tab) +				</a> +			</div> + +			<TextInput +				field={form.title} +				label={`Instance title (max ${titleLimit} characters)`} +				placeholder="My GoToSocial instance" +			/> + +			<div className="file-upload" aria-labelledby="avatar"> +				<strong id="avatar">Instance avatar</strong> +				<div> +					<img +						className="preview avatar" +						src={form.thumbnail.previewValue ?? instance?.thumbnail} +						alt={form.thumbnailDesc.value ?? (instance?.thumbnail ? `Thumbnail image for the instance` : "No instance thumbnail image set")} +					/> +					<div> +						<FileInput +							field={form.thumbnail} +							accept="image/png, image/jpeg, image/webp, image/gif" +						/> +						<br/> +						<TextInput +							field={form.thumbnailDesc} +							label="Avatar image description" +							placeholder="A cute drawing of a smiling sloth." +						/> +					</div> +				</div> + +			</div> + +			<div className="form-section-docs"> +				<h3>Descriptors</h3> +				<a +					href="https://docs.gotosocial.org/en/latest/admin/settings/#instance-descriptors" +					target="_blank" +					className="docslink" +					rel="noreferrer" +				> +					Learn more about these settings (opens in a new tab) +				</a> +			</div> + +			<TextArea +				field={form.shortDesc} +				label={`Short description (markdown accepted, max ${shortDescLimit} characters)`} +				placeholder="A small testing instance for the GoToSocial alpha software." +				rows={6} +			/> + +			<TextArea +				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" +				rows={6} +			/> + +			<TextArea +				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." +				rows={6} +			/> + +			<div className="form-section-docs"> +				<h3>Contact info</h3> +				<a +					href="https://docs.gotosocial.org/en/latest/admin/settings/#instance-contact-info" +					target="_blank" +					className="docslink" +					rel="noreferrer" +				> +					Learn more about these settings (opens in a new tab) +				</a> +			</div> + +			<TextInput +				field={form.contactUser} +				label="Contact user (local account username)" +				placeholder="admin" +			/> + +			<TextInput +				field={form.contactEmail} +				label="Contact email" +				placeholder="admin@example.com" +			/> + +			<MutationButton label="Save" result={result} disabled={false} /> +		</form> +	); +}
\ No newline at end of file diff --git a/web/source/settings/index.js b/web/source/settings/index.js index 57c89be6f..2ca396ed5 100644 --- a/web/source/settings/index.js +++ b/web/source/settings/index.js @@ -33,6 +33,8 @@ const { RoleContext } = require("./lib/navigation/util");  const DomainPerms = require("./admin/domain-permissions").default;  const DomainPermsImportExport = require("./admin/domain-permissions/import-export").default; +const InstanceSettings = require("./admin/settings").default; +  require("./style.css");  const { Sidebar, ViewRouter } = createNavigation("/settings", [ @@ -66,7 +68,7 @@ const { Sidebar, ViewRouter } = createNavigation("/settings", [  			Item("Remote", { icon: "fa-cloud" }, require("./admin/emoji/remote"))  		]),  		Menu("Settings", { icon: "fa-sliders" }, [ -			Item("Settings", { icon: "fa-sliders", url: "" }, require("./admin/settings")), +			Item("Settings", { icon: "fa-sliders", url: "" }, InstanceSettings),  			Item("Rules", { icon: "fa-dot-circle-o", wildcard: true }, require("./admin/settings/rules"))  		]),  	]) diff --git a/web/source/settings/lib/types/instance.ts b/web/source/settings/lib/types/instance.ts index a0a75366e..adc55687c 100644 --- a/web/source/settings/lib/types/instance.ts +++ b/web/source/settings/lib/types/instance.ts @@ -18,24 +18,28 @@  */  export interface InstanceV1 { -    uri:               string; -    account_domain:    string; -    title:             string; -    description:       string; -    short_description: string; -    email:             string; -    version:           string; -    languages:         any[]; // TODO: define this -    registrations:     boolean; -    approval_required: boolean; -    invites_enabled:   boolean; -    configuration:     InstanceConfiguration; -    urls:              InstanceUrls; -    stats:             InstanceStats; -    thumbnail:         string; -    contact_account:   Object; // TODO: define this. -    max_toot_chars:    number; -    rules:             any[]; // TODO: define this +    uri:                    string; +    account_domain:         string; +    title:                  string; +    description:            string; +    description_text?:       string; +    short_description:      string; +    short_description_text?: string; +    email:                  string; +    version:                string; +    languages:              any[]; // TODO: define this +    registrations:          boolean; +    approval_required:      boolean; +    invites_enabled:        boolean; +    configuration:          InstanceConfiguration; +    urls:                   InstanceUrls; +    stats:                  InstanceStats; +    thumbnail:              string; +    contact_account:        Object; // TODO: define this. +    max_toot_chars:         number; +    rules:                  any[]; // TODO: define this +    terms?:                 string; +    terms_text?:             string;  }  export interface InstanceConfiguration {  | 
