apply prettier to site files

This commit is contained in:
Dmitry Verkhoturov 2024-02-23 01:20:57 +01:00 committed by Umputun
parent 6fcfaa12b7
commit d02099844e
19 changed files with 413 additions and 397 deletions

3
site/.prettierignore Normal file
View File

@ -0,0 +1,3 @@
build
public/site.webmanifest
src/docs/configuration/parameters/index.md

View File

@ -2,6 +2,7 @@
"semi": false,
"singleQuote": true,
"arrowParens": "always",
"useTabs": true,
"overrides": [
{
"files": "*.md",

View File

@ -4,8 +4,8 @@
Requirements:
* [Node.js v20](https://nodejs.org/en/) or higher - install from package or with Homebrew
* Yarn 1.22 or higher - once you have Node.js, run `npm i -g yarn`
- [Node.js v20](https://nodejs.org/en/) or higher - install from package or with Homebrew
- Yarn 1.22 or higher - once you have Node.js, run `npm i -g yarn`
### Development

View File

@ -29,7 +29,7 @@ If running in a docker container, the command becomes (`ADMIN_PASSWD` will be ta
docker exec -it remark42 remap -s <your site ID> -f var/rules
```
The command above sends a *request* to start the remap job. You can see the job execution logs by running:
The command above sends a _request_ to start the remap job. You can see the job execution logs by running:
```shell
docker logs <container>

View File

@ -48,28 +48,28 @@ After completing the previous steps, you can configure the Apple auth provider.
4. In the left Nav pane, choose **"Credentials"**
5. In the center pane, choose the **"OAuth consent screen"** tab.
- Select "**External**" and click "Create"
- Fill in **"App name"** and select **User support email**
- Upload a logo, if you want to
- In the **App Domain** section:
- **Application home page** - your site URL, e.g., `https://mysite.com`
- **Application privacy policy link** - `/web/privacy.html` of your Remark42 installation, e.g. `https://remark42.mysite.com/web/privacy.html` (please check that it works)
- **Terms of service** - leave empty
- **Authorized domains** - your site domain, e.g., `mysite.com`
- **Developer contact information** - add your email, and then click **Save and continue**
- On the **Scopes** tab, just click **Save and continue**
- On the **Test users**, add your email, then click **Save and continue**
- Before going to the next step, set the app to "Production" and send it to verification
- Select "**External**" and click "Create"
- Fill in **"App name"** and select **User support email**
- Upload a logo, if you want to
- In the **App Domain** section:
- **Application home page** - your site URL, e.g., `https://mysite.com`
- **Application privacy policy link** - `/web/privacy.html` of your Remark42 installation, e.g. `https://remark42.mysite.com/web/privacy.html` (please check that it works)
- **Terms of service** - leave empty
- **Authorized domains** - your site domain, e.g., `mysite.com`
- **Developer contact information** - add your email, and then click **Save and continue**
- On the **Scopes** tab, just click **Save and continue**
- On the **Test users**, add your email, then click **Save and continue**
- Before going to the next step, set the app to "Production" and send it to verification
6. In the center pane, choose the **"Credentials"** tab
- Open the **"Create credentials"** drop-down
- Choose **"OAuth client ID"**
- Choose **"Web application"**
- Application **Name** is freeform; choose something appropriate, like "Comments on mysite.com"
- **Authorized JavaScript Origins** should be your domain, e.g., `https://remark42.mysite.com`
- **Authorized redirect URIs** is the location of OAuth2/callback constructed as domain + `/auth/google/callback`, e.g., `https://remark42.mysite.com/auth/google/callback`
- Click **"Create"**
- Open the **"Create credentials"** drop-down
- Choose **"OAuth client ID"**
- Choose **"Web application"**
- Application **Name** is freeform; choose something appropriate, like "Comments on mysite.com"
- **Authorized JavaScript Origins** should be your domain, e.g., `https://remark42.mysite.com`
- **Authorized redirect URIs** is the location of OAuth2/callback constructed as domain + `/auth/google/callback`, e.g., `https://remark42.mysite.com/auth/google/callback`
- Click **"Create"**
7. Take note of the **Client ID** (`AUTH_GOOGLE_CID`) and **Client Secret** (`AUTH_GOOGLE_CSEC`)
@ -124,4 +124,4 @@ For more details refer to [Yandex OAuth](https://yandex.com/dev/oauth/doc/dg/con
Optionally, anonymous access can be turned on. In this case, an extra `anonymous` provider will allow logins without any social login with any name satisfying two conditions:
- the name should be at least three characters long
- the name has to start from the letter and contains letters, numbers, underscores and spaces only**
- the name has to start from the letter and contains letters, numbers, underscores and spaces only

View File

@ -204,13 +204,13 @@ Now we have the following templates:
To replace any template, add the file with the same name to the directory with the remark42 executable file. In case you run Remark42 inside docker-compose, you can put customised templates into a directory like `customised_templates` and then mount it like that:
```yaml
volumes:
- ./var:/srv/var
- ./customised_templates/email_confirmation_login.html.tmpl:/srv/email_confirmation_login.html.tmpl:ro
- ./customised_templates/email_confirmation_subscription.html.tmpl:/srv/email_confirmation_subscription.html.tmpl:ro
- ./customised_templates/email_reply.html.tmpl:/srv/email_reply.html.tmpl:ro
- ./customised_templates/email_unsubscribe.html.tmpl:/srv/email_unsubscribe.html.tmpl:ro
- ./customised_templates/error_response.html.tmpl:/srv/error_response.html.tmpl:ro
volumes:
- ./var:/srv/var
- ./customised_templates/email_confirmation_login.html.tmpl:/srv/email_confirmation_login.html.tmpl:ro
- ./customised_templates/email_confirmation_subscription.html.tmpl:/srv/email_confirmation_subscription.html.tmpl:ro
- ./customised_templates/email_reply.html.tmpl:/srv/email_reply.html.tmpl:ro
- ./customised_templates/email_unsubscribe.html.tmpl:/srv/email_unsubscribe.html.tmpl:ro
- ./customised_templates/error_response.html.tmpl:/srv/error_response.html.tmpl:ro
```
The easiest way to test it is to mount `error_response.html.tmpl`, and then head to <http://127.0.0.1:8080/email/unsubscribe.html>, where you are supposed to see the page like the following:

View File

@ -27,18 +27,18 @@ Example with all of the params:
```html
<script>
var remark_config = {
host: 'https://remark42.example.com',
site_id: 'my_site',
components: ['embed', 'last-comments']
max_shown_comments: 100,
theme: 'dark',
page_title: 'My custom title for a page',
locale: 'es',
show_email_subscription: false,
simple_view: true,
no_footer: false
}
var remark_config = {
host: 'https://remark42.example.com',
site_id: 'my_site',
components: ['embed', 'last-comments']
max_shown_comments: 100,
theme: 'dark',
page_title: 'My custom title for a page',
locale: 'es',
show_email_subscription: false,
simple_view: true,
no_footer: false
}
</script>
```
@ -92,11 +92,11 @@ Add this snippet to the bottom of web page, or adjust already present `remark_co
```html
<script>
var remark_config = {
host: "REMARK_URL",
site_id: "YOUR_SITE_ID",
components: ["last-comments"],
}
var remark_config = {
host: "REMARK_URL",
site_id: "YOUR_SITE_ID",
components: ["last-comments"],
}
</script>
```
@ -119,11 +119,11 @@ Add this snippet to the bottom of web page, or adjust already present `remark_co
```html
<script>
var remark_config = {
host: "REMARK_URL",
site_id: "YOUR_SITE_ID",
components: ["counter"],
}
var remark_config = {
host: "REMARK_URL",
site_id: "YOUR_SITE_ID",
components: ["counter"],
}
</script>
```
@ -135,8 +135,8 @@ And then add a node like this in the place where you want to see a number of com
```html
<span
class="remark42__counter"
data-url="https://domain.com/path/to/article/"
class="remark42__counter"
data-url="https://domain.com/path/to/article/"
></span>
```

View File

@ -1,4 +1,3 @@
## API for Single-Page Application
Add the following JavaScript to your `index.html`, which in this case, it is identical to `<script defer src="$HOST/web/embed.js"></script>`

View File

@ -13,7 +13,7 @@ Most of the parameters have sane defaults and don't require customization. There
The minimal `docker-compose.yml` has to include all required parameters:
```yaml
version: '2'
version: "2"
services:
remark42:
@ -21,14 +21,14 @@ services:
restart: always
container_name: "remark42"
environment:
- REMARK_URL=https://demo.remark42.com # URL pointing to your Remark42 server
- SITE=YOUR_SITE_ID # site ID, same as used for `site_id`, see "Setup on your website"
- SECRET=abcd-123456-xyz-$%^& # secret key
- AUTH_ANON=true # enable anonymous commenting
- AUTH_GITHUB_CID=12345667890 # OAuth2 client ID
- AUTH_GITHUB_CSEC=abcdefg12345678 # OAuth2 client secret
- REMARK_URL=https://demo.remark42.com # URL pointing to your Remark42 server
- SITE=YOUR_SITE_ID # site ID, same as used for `site_id`, see "Setup on your website"
- SECRET=abcd-123456-xyz-$%^& # secret key
- AUTH_ANON=true # enable anonymous commenting
- AUTH_GITHUB_CID=12345667890 # OAuth2 client ID
- AUTH_GITHUB_CSEC=abcdefg12345678 # OAuth2 client secret
volumes:
- ./var:/srv/var # persistent volume to store all Remark42 data
- ./var:/srv/var # persistent volume to store all Remark42 data
```
### Complete parameters list
@ -208,7 +208,7 @@ To get a user ID just log in and click on your username or any other user you wa
Two parameters allow customizing the Docker container on the system level:
* `APP_UID` - sets UID to run Remark42 application in container (default=1001)
* `TIME_ZONE` - sets time zone of Remark42 container, would be used only on the backend as comments shown with user's timezone in the web interface (default=America/Chicago)
- `APP_UID` - sets UID to run Remark42 application in container (default=1001)
- `TIME_ZONE` - sets time zone of Remark42 container, would be used only on the backend as comments shown with user's timezone in the web interface (default=America/Chicago)
_See [umputun/baseimage](https://github.com/umputun/baseimage) for more details._

View File

@ -49,9 +49,10 @@ To integrate notifications about any comment on your sites with remark42 with [T
1. Set `NOTIFY_ADMINS=telegram`
2. Make [a channel](https://telegram.org/faq_channels), **add your bot as Administrator** into it and add channel ID to remark42 configuration as `NOTIFY_TELEGRAM_CHAN`
* "Post messages" permission is enough for bot to be able to post messages in your channel, others are unnecessary;
* To obtain a public channel ID, forward any message from it to [@JsonDumpBot](https://t.me/JsonDumpBot): look for `id` in `forward_from_chat`;
* If you want to use a private channel or chat, use [these instructions](https://github.com/GabrielRF/telegram-id#web-channel-id) to obtain the ID.
- "Post messages" permission is enough for bot to be able to post messages in your channel, others are unnecessary;
- To obtain a public channel ID, forward any message from it to [@JsonDumpBot](https://t.me/JsonDumpBot): look for `id` in `forward_from_chat`;
- If you want to use a private channel or chat, use [these instructions](https://github.com/GabrielRF/telegram-id#web-channel-id) to obtain the ID.
### Notifications for users

View File

@ -143,6 +143,7 @@ Streaming API supposed to provide server-sent events for post updates as well as
- `GET /api/v1/stream/last?site=site-id&since=unix_ts_msec` - returns updates stream (`event: last`) with comments for the site, `since` is optional
It was removed in https://github.com/umputun/remark42/pull/826 due to not being used and affecting tests flakiness and could be returned if there will be a developer who would be willing to write frontend support for it.
</details>
<details><summary>Response example</summary>

View File

@ -29,10 +29,10 @@ Add config for Remark on a page of your site ([here](/docs/configuration/fronten
```html
<script>
var remark_config = {
host: 'REMARK_URL',
site_id: 'YOUR_SITE_ID',
}
var remark_config = {
host: "REMARK_URL",
site_id: "YOUR_SITE_ID",
}
</script>
```
@ -40,10 +40,10 @@ For example:
```html
<script>
var remark_config = {
host: 'https://demo.remark42.com',
site_id: 'remark',
}
var remark_config = {
host: "https://demo.remark42.com",
site_id: "remark",
}
</script>
```
@ -76,5 +76,5 @@ To verify if Remark42 has been properly installed, check a demo page at `${REMAR
### Build from the source
* to build Docker container - `make docker`. This command will produce container `umputun/remark42`
* to build a single binary for direct execution - `make OS=<linux|windows|darwin> ARCH=<amd64|386>`. This step will produce an executable `remark42` file with everything embedded
- to build Docker container - `make docker`. This command will produce container `umputun/remark42`
- to build a single binary for direct execution - `make OS=<linux|windows|darwin> ARCH=<amd64|386>`. This step will produce an executable `remark42` file with everything embedded

View File

@ -10,10 +10,12 @@
While Astro supports numerous front-end framework [integrations](https://docs.astro.build/en/guides/integrations-guide/#official-integrations) (e.g. React, Vue, SolidJS, etc.)
## w/ Svelte Components
### Svelte Component (Embedded Frame)
#### remark42-embed.svelte
```js
<svelte:head>
<script async lang="javascript">
@ -42,7 +44,9 @@ While Astro supports numerous front-end framework [integrations](https://docs.as
```
### Astro Layout (Page)
#### blogpageLayout.astro (partial Astro layout)
```js
---
...
@ -63,10 +67,13 @@ const { frontmatter } = Astro.props;
...
</html>
```
Note the use of the `client:visible` directive which will hydrate the component once the element becomes visible.
### Svelte Component (Counter)
#### remark42-counter.svelte
```js
<script>
export let url;
@ -99,7 +106,9 @@ Note the use of the `client:visible` directive which will hydrate the component
```
### Astro Component (Card)
#### blogCard.astro (partial Astro component)
```js
---
const { post } = Astro.props;
@ -121,6 +130,7 @@ import Remark42Count from "../components/remark42-count.svelte";
...
</div>
```
Note the use of the `client:idle` directive which will hydrate the component once the page has completed the initial load.
## w/ React/Preact Components
@ -128,35 +138,36 @@ Note the use of the `client:idle` directive which will hydrate the component onc
This example demonstrates how to integrate the Remark42 commenting system using a React/Preact component. The component manages the insertion and removal of the Remark42 script in the DOM, provides the ability to toggle between light and dark themes, and includes areas for embedding comments and displaying a comment count. This makes it easy to incorporate a commenting system into a React/Preact application.
#### Comment.tsx
```ts
import {useEffect, useState} from 'preact/hooks'
import { useEffect, useState } from "preact/hooks"
declare global {
// Declare the global types for REMARK42 and remark_config so they can be used in this module.
interface Window {
REMARK42: any
remark_config: any
}
// Declare the global types for REMARK42 and remark_config so they can be used in this module.
interface Window {
REMARK42: any
remark_config: any
}
}
// Function to insert the Remark42 script into the DOM.
const insertScript = (id: string, parentElement: HTMLElement) => {
const script = window.document.createElement('script')
script.type = 'text/javascript'
script.async = true
script.id = id
const script = window.document.createElement("script")
script.type = "text/javascript"
script.async = true
script.id = id
// Get the current URL, and remove trailing slash if it exists.
let url = window.location.origin + window.location.pathname
if (url.endsWith('/')) {
url = url.slice(0, -1)
}
// Get the current URL, and remove trailing slash if it exists.
let url = window.location.origin + window.location.pathname
if (url.endsWith("/")) {
url = url.slice(0, -1)
}
// Get the host from the environment variables.
const host = import.meta.env.PUBLIC_REMARK_URL
// Get the host from the environment variables.
const host = import.meta.env.PUBLIC_REMARK_URL
// Set the inner HTML of the script to load Remark42.
script.innerHTML = `
// Set the inner HTML of the script to load Remark42.
script.innerHTML = `
var remark_config = {
host: "${host}",
site_id: "remark",
@ -166,67 +177,69 @@ const insertScript = (id: string, parentElement: HTMLElement) => {
};
!function(e,n){for(var o=0;o<e.length;o++){var r=n.createElement("script"),c=".js",d=n.head||n.body;"noModule"in r?(r.type="module",c=".mjs"):r.async=!0,r.defer=!0,r.src=remark_config.host+"/web/"+e[o]+c,d.appendChild(r)}}(remark_config.components||["embed"],document);`
// Append the script to the parent element.
parentElement.appendChild(script)
// Append the script to the parent element.
parentElement.appendChild(script)
}
// Function to remove the Remark42 script from the DOM.
const removeScript = (id: string, parentElement: HTMLElement) => {
const script = window.document.getElementById(id)
if (script) {
parentElement.removeChild(script)
}
const script = window.document.getElementById(id)
if (script) {
parentElement.removeChild(script)
}
}
// Function to manage the insertion and removal of the Remark42 script.
const manageScript = () => {
if (!window) {
return () => {}
}
const {document} = window
if (document.getElementById('remark42')) {
insertScript('comments-script', document.body)
}
if (!window) {
return () => {}
}
const { document } = window
if (document.getElementById("remark42")) {
insertScript("comments-script", document.body)
}
// Return a cleanup function to remove the script when the component unmounts.
return () => removeScript('comments-script', document.body)
// Return a cleanup function to remove the script when the component unmounts.
return () => removeScript("comments-script", document.body)
}
export function Comments() {
// State for tracking the current theme.
const [theme, setTheme] = useState('dark')
// State for tracking the current theme.
const [theme, setTheme] = useState("dark")
// Use effect to manage the Remark42 script.
useEffect(manageScript, [])
// Use effect to manage the Remark42 script.
useEffect(manageScript, [])
// Use effect to update the theme when it changes.
useEffect(() => {
if (window.REMARK42) {
window.REMARK42.changeTheme(theme)
}
}, [theme])
// Use effect to update the theme when it changes.
useEffect(() => {
if (window.REMARK42) {
window.REMARK42.changeTheme(theme)
}
}, [theme])
// Function to toggle the theme.
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'dark' ? 'light' : 'dark'))
}
// Function to toggle the theme.
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "dark" ? "light" : "dark"))
}
return (
<>
<h2>Comments</h2>
{/* Button to change the theme. */}
<button onClick={toggleTheme}>Change Theme</button>
{/* The span where Remark42 will embed the comment count. */}
<p>
There are <span className="remark42__counter"></span> comments.
</p>
{/* The div where Remark42 will embed the comments. */}
<div id="remark42"></div>
</>
)
return (
<>
<h2>Comments</h2>
{/* Button to change the theme. */}
<button onClick={toggleTheme}>Change Theme</button>
{/* The span where Remark42 will embed the comment count. */}
<p>
There are <span className="remark42__counter"></span> comments.
</p>
{/* The div where Remark42 will embed the comments. */}
<div id="remark42"></div>
</>
)
}
```
#### Here how to use it in your Astro component.
```js
---
import { Comments } from "@components/Comment";

View File

@ -1,18 +1,18 @@
# Using Remark42 in Gatsby projects
## React component written in Javascript
```js
import * as React from "react"
// This function will insert the usual <script> tag of
// Remark42 into the specified DOM location (parentElement)
const insertScript = (id, parentElement) => {
const script = window.document.createElement("script")
script.type = "text/javascript"
script.async = true
script.id = id
/* For Gatsby it's important to manually provide the URL
const script = window.document.createElement("script")
script.type = "text/javascript"
script.async = true
script.id = id
/* For Gatsby it's important to manually provide the URL
and make sure it does not contain a trailing slash ("/").
Because otherwise the comments for paths with/without
the trailing slash are stored separately in the BoltDB database.
@ -22,12 +22,12 @@ const insertScript = (id, parentElement) => {
your comments from the inverse URL at your present URL.
Making sure url is provided without the trailing slash
in the remark42 config solves this. */
let url = window.location.origin + window.location.pathname
if(url.endsWith("/")) {
url = url.slice(0, -1)
}
// Now the actual config and script-fetching function:
script.innerHTML = `
let url = window.location.origin + window.location.pathname
if (url.endsWith("/")) {
url = url.slice(0, -1)
}
// Now the actual config and script-fetching function:
script.innerHTML = `
var remark_config = {
host: "https://remark42.example.com",
site_id: "example-name",
@ -36,7 +36,7 @@ const insertScript = (id, parentElement) => {
components: ["embed"],
};
!function(e,n){for(var o=0;o<e.length;o++){var r=n.createElement("script"),c=".js",d=n.head||n.body;"noModule"in r?(r.type="module",c=".mjs"):r.async=!0,r.defer=!0,r.src=remark_config.host+"/web/"+e[o]+c,d.appendChild(r)}}(remark_config.components||["embed"],document);`
parentElement.appendChild(script)
parentElement.appendChild(script)
}
/* This function removes the previously added script from the DOM.
@ -44,79 +44,78 @@ Might be necessary when page transitions happen, to make sure a new instance
is created, pointing to the current URL. Although this might actually
not be necessary, please do your own testing.*/
const removeScript = (id, parentElement) => {
const script = window.document.getElementById(id)
if (script) {
parentElement.removeChild(script)
}
const script = window.document.getElementById(id)
if (script) {
parentElement.removeChild(script)
}
}
// This function will be provided to useEffect and will insert the script
// when the component is mounted and remove it when it unmounts
const manageScript = () => {
if (!window) {
return
}
const document = window.document
if (document.getElementById("remark42")) {
insertScript("comments-script", document.body)
}
return () => removeScript("comments-script", document.body)
if (!window) {
return
}
const document = window.document
if (document.getElementById("remark42")) {
insertScript("comments-script", document.body)
}
return () => removeScript("comments-script", document.body)
}
/* Another function for another useEffect - this is the most crucial part for
Gatsby compatibility. It will ensure that each page loads its own appropriate
comments, and that comments will be properly loaded */
const recreateRemark42Instance = () => {
if (!window) {
return
}
const remark42 = window.REMARK42
if (remark42) {
remark42.destroy()
remark42.createInstance(window.remark_config)
}
if (!window) {
return
}
const remark42 = window.REMARK42
if (remark42) {
remark42.destroy()
remark42.createInstance(window.remark_config)
}
}
// The location prop is {props.location.pathname} from the parent component.
// I.e. invoke the component like this in the parent: <Comments location={props.location.pathname} />
const Comments = ({ location }) => {
// Insert the two useEffect hooks. Maybe you can combine them into one? Feel free if you want to.
React.useEffect(manageScript, [location])
React.useEffect(recreateRemark42Instance, [location])
// Insert the two useEffect hooks. Maybe you can combine them into one? Feel free if you want to.
React.useEffect(manageScript, [location])
React.useEffect(recreateRemark42Instance, [location])
return (
<>
<h2>Comments</h2>
{ /* This div is the target for actual comments insertion */ }
<div id="remark42"></div>
</>
)
return (
<>
<h2>Comments</h2>
{/* This div is the target for actual comments insertion */}
<div id="remark42"></div>
</>
)
}
export default Comments
```
## React component written in Typescript
```ts
import { Fragment, useEffect } from 'react';
import { Fragment, useEffect } from "react"
declare global {
interface Window {
REMARK42: any;
remark_config: any;
}
interface Window {
REMARK42: any
remark_config: any
}
}
// This function will insert the usual <script> tag of
// Remark42 into the specified DOM location (parentElement)
const insertScript = (id: string, parentElement: HTMLElement) => {
const script = window.document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.id = id;
/* For Gatsby it's important to manually provide the URL
const script = window.document.createElement("script")
script.type = "text/javascript"
script.async = true
script.id = id
/* For Gatsby it's important to manually provide the URL
and make sure it does not contain a trailing slash ("/").
Because otherwise the comments for paths with/without
the trailing slash are stored separately in the BoltDB database.
@ -126,12 +125,12 @@ const insertScript = (id: string, parentElement: HTMLElement) => {
your comments from the inverse URL at your present URL.
Making sure url is provided without the trailing slash
in the remark42 config solves this. */
let url = window.location.origin + window.location.pathname;
if (url.endsWith('/')) {
url = url.slice(0, -1);
}
// Now the actual config and script-fetching function:
script.innerHTML = `
let url = window.location.origin + window.location.pathname
if (url.endsWith("/")) {
url = url.slice(0, -1)
}
// Now the actual config and script-fetching function:
script.innerHTML = `
var remark_config = {
host: "https://remark42.example.com",
site_id: "example-name",
@ -139,66 +138,65 @@ const insertScript = (id: string, parentElement: HTMLElement) => {
theme: "dark",
components: ["embed"],
};
!function(e,n){for(var o=0;o<e.length;o++){var r=n.createElement("script"),c=".js",d=n.head||n.body;"noModule"in r?(r.type="module",c=".mjs"):r.async=!0,r.defer=!0,r.src=remark_config.host+"/web/"+e[o]+c,d.appendChild(r)}}(remark_config.components||["embed"],document);`;
parentElement.appendChild(script);
};
!function(e,n){for(var o=0;o<e.length;o++){var r=n.createElement("script"),c=".js",d=n.head||n.body;"noModule"in r?(r.type="module",c=".mjs"):r.async=!0,r.defer=!0,r.src=remark_config.host+"/web/"+e[o]+c,d.appendChild(r)}}(remark_config.components||["embed"],document);`
parentElement.appendChild(script)
}
/* This function removes the previously added script from the DOM.
Might be necessary when page transitions happen, to make sure a new instance
is created, pointing to the current URL. Although this might actually
not be necessary, please do your own testing. */
const removeScript = (id: string, parentElement: HTMLElement) => {
const script = window.document.getElementById(id);
if (script) {
parentElement.removeChild(script);
}
};
const script = window.document.getElementById(id)
if (script) {
parentElement.removeChild(script)
}
}
// This function will be provided to useEffect and will insert the script
// when the component is mounted and remove it when it unmounts
const manageScript = () => {
if (!window) {
return () => {};
}
const { document } = window;
if (document.getElementById('remark42')) {
insertScript('comments-script', document.body);
}
return () => removeScript('comments-script', document.body);
};
if (!window) {
return () => {}
}
const { document } = window
if (document.getElementById("remark42")) {
insertScript("comments-script", document.body)
}
return () => removeScript("comments-script", document.body)
}
/* Another function for another useEffect - this is the most crucial part for
Gatsby compatibility. It will ensure that each page loads its own appropriate
comments, and that comments will be properly loaded */
const recreateRemark42Instance = () => {
if (!window) {
return;
}
const remark42 = window.REMARK42;
if (remark42) {
remark42.destroy();
remark42.createInstance(window.remark_config);
}
};
if (!window) {
return
}
const remark42 = window.REMARK42
if (remark42) {
remark42.destroy()
remark42.createInstance(window.remark_config)
}
}
type CommentsProps = {
location: string;
};
location: string
}
// The location prop is {props.location.pathname} from the parent component.
// I.e. invoke the component like this in the parent: <Comments location={props.location.pathname} />
export function Comments({ location }: CommentsProps) {
// Insert the two useEffect hooks. Maybe you can combine them into one? Feel free if you want to.
useEffect(manageScript, [location]);
useEffect(recreateRemark42Instance, [location]);
// Insert the two useEffect hooks. Maybe you can combine them into one? Feel free if you want to.
useEffect(manageScript, [location])
useEffect(recreateRemark42Instance, [location])
return (
<Fragment>
<h2>Comments</h2>
{/* This div is the target for actual comments insertion */}
<div id="remark42" />
</Fragment>
);
return (
<Fragment>
<h2>Comments</h2>
{/* This div is the target for actual comments insertion */}
<div id="remark42" />
</Fragment>
)
}
```

View File

@ -16,7 +16,7 @@ Set `ALLOWED_HOSTS='self',example1.org,example2.org` with your domain names and
`ALLOWED_HOSTS` sets CSP [frame-ancestors](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors), which, once enabled, limits the domains where Remark42 would work. The default value is not set so that it would work on any domain.
`AUTH_SAME_SITE` sets the [SAME_SITE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) attribute for authorisation cookies, allowing Remark42 either on the original domain and subdomains there (default value, not set which equals to `Lax`) or allows setting authorisation cookies on any domain where remark42 is shown (`None` setting).
`AUTH_SAME_SITE` sets the [SAME_SITE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) attribute for authorisation cookies, allowing Remark42 either on the original domain and subdomains there (default value, not set which equals to `Lax`) or allows setting authorisation cookies on any domain where remark42 is shown (`None` setting).
Here are all possible combinations of these two:

View File

@ -73,7 +73,7 @@ example.com {
handle_path /remark42* {
reverse_proxy remark42:8080
}
file_server
}
```

View File

@ -1,123 +1,123 @@
[
{
"section": "Getting Started",
"children": [
{
"title": "Installation",
"href": "/getting-started/installation/"
}
]
},
{
"section": "Configuration",
"children": [
{
"title": "Frontend configuration",
"href": "/configuration/frontend/"
},
{
"title": "Backend configuration",
"href": "/configuration/parameters/"
},
{
"title": "Authorization",
"href": "/configuration/authorization/"
},
{
"title": "Notifications",
"href": "/configuration/notifications/"
},
{
"title": "Email",
"href": "/configuration/email/"
},
{
"title": "Telegram",
"href": "/configuration/telegram/"
}
]
},
{
"section": "Manuals",
"children": [
{
"title": "Admin UI",
"href": "/manuals/admin-interface/"
},
{
"title": "Without subdomain",
"href": "/manuals/subdomain/"
},
{
"title": "On a separate domain",
"href": "/manuals/separate-domain/"
},
{
"title": "Reproxy",
"href": "/manuals/reproxy/"
},
{
"title": "Nginx",
"href": "/manuals/nginx/"
},
{
"title": "Kubernetes",
"href": "/manuals/kubernetes/"
},
{
"title": "Astro Integration (w/Svelte)",
"href": "/manuals/integration-with-astro/"
},
{
"title": "Gatsby Integration",
"href": "/manuals/integration-with-gatsby/"
},
{
"title": "Anti-Spam",
"href": "/manuals/spam/"
}
]
},
{
"section": "Backup",
"children": [
{
"title": "Backup",
"href": "/backup/backup/"
},
{
"title": "Restore",
"href": "/backup/restore/"
},
{
"title": "Migration",
"href": "/backup/migration/"
},
{
"title": "Site URL migration",
"href": "/backup/url-migration/"
}
]
},
{
"section": "Contributing",
"children": [
{
"title": "Backend",
"href": "/contributing/backend/"
},
{
"title": "Frontend",
"href": "/contributing/frontend/"
},
{
"title": "Translations",
"href": "/contributing/translations/"
},
{
"title": "API",
"href": "/contributing/api/"
}
]
}
{
"section": "Getting Started",
"children": [
{
"title": "Installation",
"href": "/getting-started/installation/"
}
]
},
{
"section": "Configuration",
"children": [
{
"title": "Frontend configuration",
"href": "/configuration/frontend/"
},
{
"title": "Backend configuration",
"href": "/configuration/parameters/"
},
{
"title": "Authorization",
"href": "/configuration/authorization/"
},
{
"title": "Notifications",
"href": "/configuration/notifications/"
},
{
"title": "Email",
"href": "/configuration/email/"
},
{
"title": "Telegram",
"href": "/configuration/telegram/"
}
]
},
{
"section": "Manuals",
"children": [
{
"title": "Admin UI",
"href": "/manuals/admin-interface/"
},
{
"title": "Without subdomain",
"href": "/manuals/subdomain/"
},
{
"title": "On a separate domain",
"href": "/manuals/separate-domain/"
},
{
"title": "Reproxy",
"href": "/manuals/reproxy/"
},
{
"title": "Nginx",
"href": "/manuals/nginx/"
},
{
"title": "Kubernetes",
"href": "/manuals/kubernetes/"
},
{
"title": "Astro Integration (w/Svelte)",
"href": "/manuals/integration-with-astro/"
},
{
"title": "Gatsby Integration",
"href": "/manuals/integration-with-gatsby/"
},
{
"title": "Anti-Spam",
"href": "/manuals/spam/"
}
]
},
{
"section": "Backup",
"children": [
{
"title": "Backup",
"href": "/backup/backup/"
},
{
"title": "Restore",
"href": "/backup/restore/"
},
{
"title": "Migration",
"href": "/backup/migration/"
},
{
"title": "Site URL migration",
"href": "/backup/url-migration/"
}
]
},
{
"section": "Contributing",
"children": [
{
"title": "Backend",
"href": "/contributing/backend/"
},
{
"title": "Frontend",
"href": "/contributing/frontend/"
},
{
"title": "Translations",
"href": "/contributing/translations/"
},
{
"title": "API",
"href": "/contributing/api/"
}
]
}
]

View File

@ -8,41 +8,41 @@ title: Remark42 Privacy-focused lightweight commenting engine
Remark42 allows you to have a self-hosted, lightweight, and simple (yet functional) comment engine, which doesn't spy on users. It can be embedded into blogs, articles or any other place where readers add comments.
* Social login via Google, Twitter, Facebook, Microsoft, GitHub, Apple, Yandex, Patreon and Telegram
* Login via email
* Optional anonymous access
* Multi-level nested comments with both tree and plain presentations
* Import from Disqus and WordPress
* Markdown support with friendly formatter toolbar
* Moderators can remove comments and block users
* Voting, pinning and verification system
* Sortable comments
* Images upload with drag-and-drop
* Extractor for recent comments, cross-post
* RSS for all comments and each post
* Telegram, Slack, email and webhook admin notifications for each new comment on your site
* Email and Telegram notifications for users so that they get notified when someone responds to their comments
* Export data to JSON with automatic backups
* No external databases, everything embedded in a single data file
* Fully dockerized and can be deployed in a single command
* A self-contained executable can be deployed directly to Linux, Windows and macOS
* Clean, lightweight and customizable UI with white and dark themes
* Multi-site mode from a single instance
* Integration with automatic SSL (direct or via reproxy)
* Privacy-focused
- Social login via Google, Twitter, Facebook, Microsoft, GitHub, Apple, Yandex, Patreon and Telegram
- Login via email
- Optional anonymous access
- Multi-level nested comments with both tree and plain presentations
- Import from Disqus and WordPress
- Markdown support with friendly formatter toolbar
- Moderators can remove comments and block users
- Voting, pinning and verification system
- Sortable comments
- Images upload with drag-and-drop
- Extractor for recent comments, cross-post
- RSS for all comments and each post
- Telegram, Slack, email and webhook admin notifications for each new comment on your site
- Email and Telegram notifications for users so that they get notified when someone responds to their comments
- Export data to JSON with automatic backups
- No external databases, everything embedded in a single data file
- Fully dockerized and can be deployed in a single command
- A self-contained executable can be deployed directly to Linux, Windows and macOS
- Clean, lightweight and customizable UI with white and dark themes
- Multi-site mode from a single instance
- Integration with automatic SSL (direct or via reproxy)
- Privacy-focused
## Privacy
* Remark42 is trying to be very sensitive to any private or semi-private information.
* Authentication is requesting the minimal possible scope from authentication providers and all extra information returned by them is immediately dropped and not stored in any form.
* Generally, Remark42 keeps user ID, username and avatar link only. None of these fields exposed directly - ID and name hashed, avatar proxied.
* There is no tracking of any sort.
* Login mechanic uses JWT stored in a cookie (HttpOnly, secured). The second cookie (XSRF_TOKEN) is a random ID preventing CSRF.
* There is no cross-site login, i.e., user's behavior can't be analyzed across independent sites running Remark42.
* There are no third-party analytic services involved.
* Users can request all information Remark42 knows about them and receive the export in the gz file.
* Supports complete cleanup of all information related to user's activity by user's "deleteme" request.
* Cookie lifespan can be restricted to session-only.
* All potentially sensitive data stored by Remark42 hashed and encrypted.
- Remark42 is trying to be very sensitive to any private or semi-private information.
- Authentication is requesting the minimal possible scope from authentication providers and all extra information returned by them is immediately dropped and not stored in any form.
- Generally, Remark42 keeps user ID, username and avatar link only. None of these fields exposed directly - ID and name hashed, avatar proxied.
- There is no tracking of any sort.
- Login mechanic uses JWT stored in a cookie (HttpOnly, secured). The second cookie (XSRF_TOKEN) is a random ID preventing CSRF.
- There is no cross-site login, i.e., user's behavior can't be analyzed across independent sites running Remark42.
- There are no third-party analytic services involved.
- Users can request all information Remark42 knows about them and receive the export in the gz file.
- Supports complete cleanup of all information related to user's activity by user's "deleteme" request.
- Cookie lifespan can be restricted to session-only.
- All potentially sensitive data stored by Remark42 hashed and encrypted.
<div class="text-right italic">— The Remark42 Team</div>

View File

@ -12,9 +12,9 @@ pagination:
alias: redirect
# Add your redirection tuples to this list!
redirects:
- { 'from': '/docs/', 'destination': '/docs/getting-started/installation/' }
- { "from": "/docs/", "destination": "/docs/getting-started/installation/" }
# The "permalink" attribute determines where the output page will be located.
permalink: '{{ redirect.from }}'
permalink: "{{ redirect.from }}"
# The "redirect" layout just has a small html header with the meta tags that do redirection.
layout: redirect
---