From f520e30858b9d646040218675d3dcddf3330540d Mon Sep 17 00:00:00 2001
From: Lim Chee Aun
Date: Mon, 25 Dec 2023 19:25:48 +0800
Subject: [PATCH] Extend self-hosting variables
---
.env | 7 ++--
README.md | 62 ++++++++++++++++++++++++++--
compose/index.html | 2 +-
index.html | 12 +++---
scripts/fetch-lingva-languages.js | 5 +--
src/components/translation-block.jsx | 15 +++----
src/pages/login.jsx | 21 +++++++---
src/pages/settings.jsx | 15 ++++++-
src/pages/welcome.css | 12 ++++++
src/pages/welcome.jsx | 57 ++++++++++++++++++++-----
src/utils/auth.js | 2 +-
src/utils/useTitle.js | 2 +-
vite.config.js | 17 +++++---
13 files changed, 179 insertions(+), 50 deletions(-)
diff --git a/.env b/.env
index 787c8d7e..23232209 100644
--- a/.env
+++ b/.env
@@ -1,3 +1,4 @@
-VITE_CLIENT_NAME=Phanpy
-VITE_CLIENT_ID=social.phanpy
-VITE_WEBSITE=https://phanpy.social
\ No newline at end of file
+PHANPY_CLIENT_NAME=Phanpy
+PHANPY_WEBSITE=https://phanpy.social
+PHANPY_LINGVA_INSTANCES="lingva.phanpy.social lingva.lunar.icu lingva.garudalinux.org translate.plausibility.cloud"
+PHANPY_PRIVACY_POLICY_URL="https://github.com/cheeaun/phanpy/blob/main/PRIVACY.MD"
\ No newline at end of file
diff --git a/README.md b/README.md
index cc438a65..acb243ee 100644
--- a/README.md
+++ b/README.md
@@ -126,10 +126,66 @@ This is a **pure static web app**. You can host it anywhere you want.
Two ways (choose one):
-1. (Recommended) Go to [Releases](https://github.com/cheeaun/phanpy/releases) and download the latest `phanpy-dist.zip`. It's pre-built so don't need to run any install/build commands. Extract it. Serve the folder of extracted files.
-2. Download or `git clone` this repository. Build it by running `npm run build` (after `npm install`). Serve the `dist` folder.
+### Easy way
-Try search for "how to self-host static sites" as there are many ways to do it.
+Go to [Releases](https://github.com/cheeaun/phanpy/releases) and download the latest `phanpy-dist.zip` or `phanpy-dist.tar.gz`. It's pre-built so don't need to run any install/build commands. Extract it. Serve the folder of extracted files.
+
+### Custom-build way
+
+Download or `git clone` this repository. Build it by running `npm run build` (after `npm install`). Serve the `dist` folder.
+
+Customization can be done by passing environment variables to the build command. Examples:
+
+```bash
+PHANPY_APP_TITLE="Phanpy Dev" \
+ PHANPY_WEBSITE="https://dev.phanpy.social" \
+ npm run build
+```
+
+```bash
+PHANPY_DEFAULT_INSTANCE=hachyderm.io \
+ PHANPY_DEFAULT_INSTANCE_REGISTRATION_URL=https://hachyderm.io/auth/sign_up \
+ PHANPY_PRIVACY_POLICY_URL=https://hachyderm.io/privacy-policy \
+ npm run build
+```
+
+It's also possible to set them in the `.env` file.
+
+Available variables:
+
+- `PHANPY_APP_TITLE` (optional, default: `Phanpy`) affects:
+ - Web page title, shown in the browser window or tab title
+ - App title, when installed as PWA, shown in the Home screen, macOS dock, Windows taskbar, etc
+ - OpenGraph card title, when shared on social networks
+ - Client name, when [registering the app for authentication](https://docs.joinmastodon.org/client/token/#app) and shown as client used on posts in some apps/clients
+- `PHANPY_WEBSITE` (optional but recommended, default: `https://phanpy.social`) affects:
+ - Canonical URL of the website
+ - OpenGraph card URL, when shared on social networks
+ - Root path for the OpenGraph card image
+ - Client URL, when [registering the app for authentication](https://docs.joinmastodon.org/client/token/#app) and shown as client used on posts in some apps/clients
+- `PHANPY_DEFAULT_INSTANCE` (optional, no defaults):
+ - e.g. 'mastodon.social', without `https://`
+ - Default instance for log-in
+ - When logging in, the user will be redirected instantly to the instance's authentication page instead of having to manually type the instance URL and submit
+- `PHANPY_DEFAULT_INSTANCE_REGISTRATION_URL` (optional, no defaults):
+ - URL of the instance registration page
+ - E.g. `https://mastodon.social/auth/sign_up`
+- `PHANPY_PRIVACY_POLICY_URL` (optional, default to official instance's privacy policy):
+ - URL of the privacy policy page
+ - May specify the instance's own privacy policy
+- `PHANPY_LINGVA_INSTANCES` (optional, space-separated list, default: `lingva.phanpy.social [...hard-coded list of fallback instances]`):
+ - Specify a space-separated list of instances. First will be used as default before falling back to the subsequent instances. If there's only 1 instance, means no fallback.
+ - May specify a self-hosted Lingva instance, powered by either [lingva-translate](https://github.com/thedaviddelta/lingva-translate) or [lingva-api](https://github.com/cheeaun/lingva-api)
+ - List of fallback instances hard-coded in `/.env`
+ - [↗️ List of lingva-translate instances](https://github.com/thedaviddelta/lingva-translate?tab=readme-ov-file#instances)
+
+### Static site hosting
+
+Try online search for "how to self-host static sites" as there are many ways to do it.
+
+#### Lingva-translate or lingva-api hosting
+
+See documentation for [lingva-translate](https://github.com/thedaviddelta/lingva-translate) or [lingva-api](https://github.com/cheeaun/lingva-api).
## Community deployments
diff --git a/compose/index.html b/compose/index.html
index c4b3d5a1..53fdf971 100644
--- a/compose/index.html
+++ b/compose/index.html
@@ -4,7 +4,7 @@
- Compose / %VITE_CLIENT_NAME%
+ Compose / %PHANPY_CLIENT_NAME%
diff --git a/index.html b/index.html
index 44108ff5..35bb3e02 100644
--- a/index.html
+++ b/index.html
@@ -6,7 +6,7 @@
name="viewport"
content="width=device-width, initial-scale=1, viewport-fit=cover"
/>
- %VITE_CLIENT_NAME%
+ %PHANPY_CLIENT_NAME%
-
+
-
+
-
-
+
+
-
+
diff --git a/scripts/fetch-lingva-languages.js b/scripts/fetch-lingva-languages.js
index f270cabe..e4bed3f1 100644
--- a/scripts/fetch-lingva-languages.js
+++ b/scripts/fetch-lingva-languages.js
@@ -1,7 +1,6 @@
-// Fetch https://lingva.ml/api/v1/languages/{source|target}
import fs from 'fs';
-fetch('https://lingva.ml/api/v1/languages/source')
+fetch('https://lingva.phanpy.social/api/v1/languages/source')
.then((response) => response.json())
.then((json) => {
const file = './src/data/lingva-source-languages.json';
@@ -9,7 +8,7 @@ fetch('https://lingva.ml/api/v1/languages/source')
fs.writeFileSync(file, JSON.stringify(json.languages, null, '\t'), 'utf8');
});
-fetch('https://lingva.ml/api/v1/languages/target')
+fetch('https://lingva.phanpy.social/api/v1/languages/target')
.then((response) => response.json())
.then((json) => {
const file = './src/data/lingva-target-languages.json';
diff --git a/src/components/translation-block.jsx b/src/components/translation-block.jsx
index 62cb7a56..588ee1f9 100644
--- a/src/components/translation-block.jsx
+++ b/src/components/translation-block.jsx
@@ -12,19 +12,16 @@ import pmem from '../utils/pmem';
import Icon from './icon';
import Loader from './loader';
+const { PHANPY_LINGVA_INSTANCES } = import.meta.env;
+const LINGVA_INSTANCES = PHANPY_LINGVA_INSTANCES
+ ? PHANPY_LINGVA_INSTANCES.split(/\s+/)
+ : [];
+
const throttle = pThrottle({
limit: 1,
interval: 2000,
});
-// Using other API instances instead of lingva.ml because of this bug (slashes don't work):
-// https://github.com/thedaviddelta/lingva-translate/issues/68
-const LINGVA_INSTANCES = [
- 'lingva.phanpy.social',
- 'lingva.lunar.icu',
- 'lingva.garudalinux.org',
- 'translate.plausibility.cloud',
-];
let currentLingvaInstance = 0;
function _lingvaTranslate(text, source, target) {
@@ -243,4 +240,4 @@ function TranslationBlock({
);
}
-export default TranslationBlock;
+export default LINGVA_INSTANCES?.length ? TranslationBlock : () => null;
diff --git a/src/pages/login.jsx b/src/pages/login.jsx
index 307fb112..a7981510 100644
--- a/src/pages/login.jsx
+++ b/src/pages/login.jsx
@@ -12,6 +12,8 @@ import { getAuthorizationURL, registerApplication } from '../utils/auth';
import store from '../utils/store';
import useTitle from '../utils/useTitle';
+const { PHANPY_DEFAULT_INSTANCE: DEFAULT_INSTANCE } = import.meta.env;
+
function Login() {
useTitle('Log in');
const instanceURLRef = useRef();
@@ -19,6 +21,7 @@ function Login() {
const [uiState, setUIState] = useState('default');
const [searchParams] = useSearchParams();
const instance = searchParams.get('instance');
+ const submit = searchParams.get('submit');
const [instanceText, setInstanceText] = useState(
instance || cachedInstanceURL?.toLowerCase() || '',
);
@@ -129,6 +132,12 @@ function Login() {
submitInstance(selectedInstanceText);
};
+ if (submit) {
+ useEffect(() => {
+ submitInstance(instance || selectedInstanceText);
+ }, []);
+ }
+
return (