Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e45bb9506 | ||
|
|
64a2adbe1a | ||
|
|
99736db27f | ||
|
|
eb3310c537 | ||
|
|
ab2c2cf153 | ||
|
|
71b73a323a | ||
|
|
659023988e | ||
|
|
c2b9afa1a1 | ||
|
|
258dfde60e | ||
|
|
91ac907778 | ||
|
|
73da8740ee | ||
|
|
4ad0cc1366 | ||
|
|
15f2fb82a3 | ||
|
|
bd81b7c10c | ||
|
|
f6c99e949b | ||
|
|
dcde53f8ad | ||
|
|
d3aacf0d14 | ||
|
|
20be96f6f8 | ||
|
|
437892cdfa | ||
|
|
5065bb4763 | ||
|
|
baa63866f4 | ||
|
|
7c251fd067 | ||
|
|
02a369fe5c | ||
|
|
bd0db8cd57 | ||
|
|
206a26d0c1 | ||
|
|
f1ae566134 | ||
|
|
3571a18b42 | ||
|
|
abac3f0f36 | ||
|
|
db960aa024 | ||
|
|
1b5ef279bb | ||
|
|
754223571a | ||
|
|
a6eba361fc | ||
|
|
1d5811a59c | ||
|
|
ea9c5d9ecb | ||
|
|
8707f4f327 | ||
|
|
b89a1866f9 | ||
|
|
7e082158cd | ||
|
|
d5d458de11 | ||
|
|
c087400a66 | ||
|
|
34d793697c |
No files matched your search
@@ -1,70 +0,0 @@
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
node: circleci/node@6.1.0
|
||||
go: circleci/go@1.11.0
|
||||
codecov: codecov/codecov@4.1.0
|
||||
|
||||
executors:
|
||||
base:
|
||||
docker:
|
||||
- image: cimg/base:stable
|
||||
node:
|
||||
docker:
|
||||
- image: "cimg/node:20.17.0"
|
||||
go:
|
||||
docker:
|
||||
- image: cimg/go:1.22.7
|
||||
|
||||
parameters:
|
||||
trigger-app:
|
||||
type: boolean
|
||||
default: false
|
||||
run-them-all:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
## Backend
|
||||
test_app:
|
||||
executor: go
|
||||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Print the Go version"
|
||||
command: go version
|
||||
- go/load-cache
|
||||
- go/mod-download
|
||||
- go/save-cache
|
||||
- run:
|
||||
name: Run tests
|
||||
command: |
|
||||
mkdir -p /tmp/test-reports
|
||||
gotestsum --junitfile /tmp/test-reports/unit-tests.xml -- -coverprofile=/tmp/test-reports/coverage.out ./...
|
||||
- store_test_results:
|
||||
path: /tmp/test-reports
|
||||
- codecov/upload:
|
||||
flags: go
|
||||
file: /tmp/test-reports/coverage.out
|
||||
|
||||
all_projects:
|
||||
executor: base
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
echo "all"
|
||||
|
||||
workflows:
|
||||
build-app:
|
||||
when:
|
||||
or:
|
||||
- << pipeline.parameters.trigger-app >>
|
||||
- << pipeline.parameters.run-them-all >>
|
||||
jobs:
|
||||
- test_app
|
||||
|
||||
build-shared-other:
|
||||
when: << pipeline.parameters.run-them-all >>
|
||||
jobs:
|
||||
- all_projects
|
||||
@@ -1,27 +0,0 @@
|
||||
# https://circleci.com/docs/2.0/configuration-reference
|
||||
version: 2.1
|
||||
|
||||
# this allows you to use CircleCI's dynamic configuration
|
||||
# https://circleci.com/docs/2.0/dynamic-config/
|
||||
setup: true
|
||||
|
||||
# the path-filtering orb is required to continue a pipeline based on
|
||||
# https://circleci.com/developer/orbs/orb/circleci/path-filtering
|
||||
orbs:
|
||||
path-filtering: circleci/path-filtering@1.0.0
|
||||
|
||||
workflows:
|
||||
setup:
|
||||
jobs:
|
||||
- path-filtering/filter:
|
||||
mapping: |
|
||||
(cmd|internal|server|pkg|test|conf)/.* trigger-app true
|
||||
main.go|go.mod|go.sum trigger-app true
|
||||
base-revision: master # git branch name
|
||||
config-path: .circleci/conditional_config.yml
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- gh-pages
|
||||
- /release\/.+/
|
||||
- nightly
|
||||
@@ -18,7 +18,9 @@ updates:
|
||||
open-pull-requests-limit: 15
|
||||
|
||||
- package-ecosystem: npm
|
||||
directory: /ui
|
||||
# setup only for whole workspace to fix issues with package.lock,
|
||||
# SEE https://github.com/dependabot/dependabot-core/issues/4993#issuecomment-1739296001
|
||||
directory: /
|
||||
schedule:
|
||||
interval: monthly
|
||||
commit-message:
|
||||
@@ -29,18 +31,7 @@ updates:
|
||||
dev-deps:
|
||||
dependency-type: development
|
||||
open-pull-requests-limit: 15
|
||||
|
||||
- package-ecosystem: npm
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: monthly
|
||||
commit-message:
|
||||
prefix: "chore(deps/docs): "
|
||||
groups:
|
||||
deps:
|
||||
patterns:
|
||||
- "*"
|
||||
open-pull-requests-limit: 15
|
||||
versioning-strategy: increase
|
||||
|
||||
- package-ecosystem: docker
|
||||
directory: /
|
||||
|
||||
@@ -78,21 +78,12 @@ jobs:
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build UI
|
||||
id: build_ui
|
||||
run: |
|
||||
make build-frontend
|
||||
echo "ui_tarball=$(make -s pack-frontend)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Pack UI
|
||||
id: pack
|
||||
run: |
|
||||
SRC_FILE=$(pnpm pack -C ui/artalk --pack-destination ../.. | tail -n 1)
|
||||
|
||||
mkdir -p bin
|
||||
PKG_FILE="bin/artalk_frontend_nigthly_$(date +'%Y%m%d').tar.gz"
|
||||
|
||||
mv $SRC_FILE $PKG_FILE
|
||||
echo "pkg_file=$PKG_FILE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload UI
|
||||
- name: Upload UI dist
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ui-src
|
||||
@@ -102,11 +93,12 @@ jobs:
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
- name: Upload UI package
|
||||
- name: Upload UI tarball (included in release)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-ui-pkg
|
||||
path: ${{ steps.pack.outputs.pkg_file }}
|
||||
name: build-ui-tarball
|
||||
path: ${{ steps.build_ui.outputs.ui_tarball }}
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
#
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
name: Test App
|
||||
|
||||
on:
|
||||
push:
|
||||
paths: ["cmd/**", "internal/**", "server/**", "test/**", "main.go", "go.mod", "go.sum"]
|
||||
branches-ignore: ["release/*", "nightly"]
|
||||
tags-ignore: ["v*"]
|
||||
pull_request:
|
||||
paths: ["cmd/**", "internal/**", "server/**", "test/**", "main.go", "go.mod", "go.sum"]
|
||||
branches-ignore: ["release/*", "nightly"]
|
||||
|
||||
env:
|
||||
REPORT_DIR: "/tmp/test-reports"
|
||||
|
||||
jobs:
|
||||
test_app:
|
||||
name: Test Go on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: false # https://github.com/actions/setup-go/issues/483
|
||||
|
||||
- id: go-vars
|
||||
name: Get Go variables for cache
|
||||
run: |
|
||||
echo "GOCACHE=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
|
||||
echo "GOMODCACHE=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
${{ steps.go-vars.outputs.GOCACHE }}
|
||||
${{ steps.go-vars.outputs.GOMODCACHE }}
|
||||
key: go-test-${{ runner.os }}-${{ hashFiles('**/go.mod') }}
|
||||
restore-keys: |
|
||||
go-test-${{ runner.os }}
|
||||
|
||||
- name: Install tools
|
||||
run: go install gotest.tools/gotestsum@latest
|
||||
|
||||
- name: Download Go modules
|
||||
run: go mod download
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
mkdir -p $REPORT_DIR
|
||||
gotestsum --junitfile $REPORT_DIR/unit-tests.xml --jsonfile $REPORT_DIR/unit-tests.json -- -coverprofile=$REPORT_DIR/coverage.out ./...
|
||||
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Go-Test-Results-${{ runner.os }}
|
||||
path: ${{ env.REPORT_DIR }}
|
||||
|
||||
- if: matrix.os == 'ubuntu-latest'
|
||||
name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
flags: go
|
||||
file: ${{ env.REPORT_DIR }}/coverage.out
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@@ -2,12 +2,12 @@ name: Test Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["*", "!release/*", "!nightly"]
|
||||
paths: ["docs/**"]
|
||||
branches-ignore: ["release/*", "nightly"]
|
||||
tags-ignore: ["v*"]
|
||||
pull_request:
|
||||
paths: ["docs/**"]
|
||||
branches: ["*", "!release/*", "!nightly"]
|
||||
branches-ignore: ["release/*", "nightly"]
|
||||
|
||||
jobs:
|
||||
test_docs:
|
||||
|
||||
@@ -2,16 +2,17 @@ name: Test Frontend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["*", "!release/*", "!nightly"]
|
||||
paths: ["ui/**"]
|
||||
branches-ignore: ["release/*", "nightly"]
|
||||
tags-ignore: ["v*"]
|
||||
pull_request:
|
||||
paths: ["ui/**"]
|
||||
branches: ["*", "!release/*", "!nightly"]
|
||||
branches-ignore: ["release/*", "nightly"]
|
||||
|
||||
jobs:
|
||||
test_ui:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node: [18, 20]
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
@@ -44,9 +45,12 @@ jobs:
|
||||
- name: Package Build Test
|
||||
run: pnpm build:all
|
||||
|
||||
- name: Unit test
|
||||
- name: Unit Test
|
||||
run: pnpm test
|
||||
|
||||
- name: Plugins Build Test
|
||||
run: pnpm build:plugins
|
||||
|
||||
- name: Lint
|
||||
run: pnpm eslint ui && pnpm prettier --check ui
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
__debug*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
# frontend
|
||||
node_modules
|
||||
|
||||
@@ -17,6 +17,7 @@ before:
|
||||
# install dependencies
|
||||
- make install
|
||||
- make build-frontend
|
||||
- make pack-frontend
|
||||
|
||||
# build multi-platform
|
||||
builds:
|
||||
|
||||
@@ -9,6 +9,7 @@ pnpm-lock.yaml
|
||||
**/auto-imports.d.ts
|
||||
**/components.d.ts
|
||||
**/typed-router.d.ts
|
||||
**/vite.config.ts.timestamp-*
|
||||
ui/artalk/src/api/v2.ts
|
||||
docs/swagger/swagger.json
|
||||
docs/swagger/swagger.yaml
|
||||
|
||||
@@ -161,6 +161,52 @@ The compiled JavaScript and CSS files will be located in the `/public` directory
|
||||
|
||||
For more details, refer to the `scripts/build-frontend.sh` script.
|
||||
|
||||
### Publish Frontend
|
||||
|
||||
The core artalk client code is automatically deployed to NPM by GitHub Actions. The deployment process is defined in the `.github/workflows/build-ui.yml` file.
|
||||
|
||||
If you are writing a artalk plugin in monorepo, it would not be automatically deployed. You should publish it manually. To publish the plugin, first ensure your version number is updated in the `package.json` file. Then, run the following command:
|
||||
|
||||
```sh
|
||||
pnpm publish --access public
|
||||
```
|
||||
|
||||
#### Check Published Versions
|
||||
|
||||
The `pnpm check:publish` script is designed to verify that all packages in the project have the latest versions published on npm. It skips private packages automatically and allows filtering to check specific packages using the `-F` option.
|
||||
|
||||
Check all packages:
|
||||
|
||||
```sh
|
||||
pnpm check:publish
|
||||
```
|
||||
|
||||
This will initiate the process of checking all public packages in the repository to ensure they are up to date on npm.
|
||||
|
||||
### Develop and Debug `@artalk/plugin-kit` and `eslint-plugin-artalk`
|
||||
|
||||
The monorepo will default to installing the latest version of `@artalk/plugin-kit` and `eslint-plugin-artalk` from NPM published packages. To develop and debug these packages, run the following commands from the root of the repository:
|
||||
|
||||
```sh
|
||||
pnpm link --global --dir ui/eslint-plugin-artalk
|
||||
pnpm link --global --dir ui/plugin-kit
|
||||
|
||||
pnpm link eslint-plugin-artalk
|
||||
pnpm link @artalk/plugin-kit
|
||||
```
|
||||
|
||||
After executing these commands, the `eslint-plugin-artalk` and `@artalk/plugin-kit` packages will be linked to the local development environment within the monorepo workspace. You can modify the source code located in the `ui/eslint-plugin-artalk` and `ui/plugin-kit` directories, and the changes will be automatically reflected in the monorepo workspace. If you wish to unlink the packages, run the following commands:
|
||||
|
||||
```sh
|
||||
pnpm unlink eslint-plugin-artalk
|
||||
pnpm unlink @artalk/plugin-kit
|
||||
|
||||
pnpm uninstall --global eslint-plugin-artalk
|
||||
pnpm uninstall --global @artalk/plugin-kit
|
||||
```
|
||||
|
||||
For more details, refer to the [pnpm link documentation](https://pnpm.io/cli/link).
|
||||
|
||||
## Docker Development
|
||||
|
||||
### Build Docker Image
|
||||
|
||||
@@ -22,7 +22,10 @@ build:
|
||||
$(PKG_NAME)
|
||||
|
||||
build-frontend:
|
||||
./scripts/build-frontend.sh
|
||||
@./scripts/build-frontend.sh
|
||||
|
||||
pack-frontend:
|
||||
@./scripts/pack-frontend.sh
|
||||
|
||||
build-debug:
|
||||
@echo "Building Artalk for debugging..."
|
||||
@@ -73,7 +76,7 @@ docker-build:
|
||||
docker-push:
|
||||
./scripts/docker-build.sh --push
|
||||
|
||||
.PHONY: all install run build build-frontend build-debug dev \
|
||||
.PHONY: all install run build build-frontend pack-frontend build-debug dev \
|
||||
test test-coverage test-coverage-html test-frontend-e2e \
|
||||
update-i18n update-conf update-conf-docs \
|
||||
update-docs-features update-swagger \
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://hub.docker.com/r/artalk/artalk-go)
|
||||
[](https://pkg.go.dev/github.com/artalkjs/artalk/v2)
|
||||
[](https://goreportcard.com/report/github.com/ArtalkJS/Artalk)
|
||||
[](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
|
||||
[](https://codecov.io/gh/ArtalkJS/Artalk)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://www.npmjs.com/package/artalk)
|
||||
[](https://hub.docker.com/r/artalk/artalk-go)
|
||||
[](https://pkg.go.dev/github.com/artalkjs/artalk/v2)
|
||||
[](https://goreportcard.com/report/github.com/ArtalkJS/Artalk)
|
||||
[](https://circleci.com/gh/ArtalkJS/Artalk/tree/master)
|
||||
[](https://codecov.io/gh/ArtalkJS/Artalk)
|
||||
|
||||
@@ -4,11 +4,14 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"syscall"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/artalkjs/artalk/v2/internal/config"
|
||||
"github.com/artalkjs/artalk/v2/internal/core"
|
||||
"github.com/artalkjs/artalk/v2/internal/log"
|
||||
"github.com/artalkjs/artalk/v2/internal/utils"
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -64,11 +67,11 @@ func New() *ArtalkCmd {
|
||||
// Parse base flags
|
||||
cmd.eagerParseFlags()
|
||||
|
||||
// Change work directory
|
||||
if cmd.workDir != "" {
|
||||
if err := os.Chdir(cmd.workDir); err != nil {
|
||||
log.Fatal("Working directory change error: ", err)
|
||||
}
|
||||
// Init data directory (work directory)
|
||||
if workDir, err := initDataDir(cmd.workDir); err == nil {
|
||||
cmd.workDir = workDir
|
||||
} else {
|
||||
log.Fatal("Data directory fail: ", err)
|
||||
}
|
||||
|
||||
return cmd
|
||||
@@ -167,16 +170,50 @@ func (atk *ArtalkCmd) Launch() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func initDataDir(workDir string) (string, error) {
|
||||
// If work directory is not specified, try to find it
|
||||
if workDir == "" {
|
||||
// If `data` in current directory exists, not change work directory
|
||||
if utils.CheckDirExist("./data") {
|
||||
// log.Warn("[DEPRECATED] The `data` directory is deprecated, please move to `~/.local/share/artalk/data`")
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Retrieve data directory assuming it's already exists
|
||||
workDir = config.RetrieveDataDir()
|
||||
}
|
||||
|
||||
// Create new data directory if not exists
|
||||
if workDir == "" {
|
||||
// default data path is `~/.local/share/artalk`
|
||||
workDir = path.Join(xdg.DataHome, "artalk")
|
||||
if err := utils.EnsureDir(workDir); err != nil {
|
||||
return "", fmt.Errorf("data directory creation error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Change work directory
|
||||
if workDir != "" {
|
||||
if err := os.Chdir(workDir); err != nil {
|
||||
return "", fmt.Errorf("working directory change error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return workDir, nil
|
||||
}
|
||||
|
||||
// Create new config instance by specific config filename
|
||||
func getConfig(cfgFile string) (*config.Config, error) {
|
||||
// Retrieve config file by default names when specific filename is empty
|
||||
// If config file is not specified, try to find it
|
||||
if cfgFile == "" {
|
||||
// Retrieve config file assuming it's already exists
|
||||
cfgFile = config.RetrieveConfigFile()
|
||||
}
|
||||
|
||||
// Generate new config file when retrieve failed
|
||||
// Generate new config file if not exists
|
||||
if cfgFile == "" {
|
||||
cfgFile = config.CONF_DEFAULT_FILENAMES[0]
|
||||
// default config path is `~/.config/artalk/artalk.yml`
|
||||
cfgFile = path.Join(xdg.ConfigHome, "artalk", config.CONF_DEFAULT_FILENAMES[0])
|
||||
core.Gen("config", cfgFile, false)
|
||||
}
|
||||
|
||||
|
||||
@@ -401,7 +401,7 @@ frontend:
|
||||
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
|
||||
# Vote button
|
||||
vote: true
|
||||
# Dislike button
|
||||
# Vote down button
|
||||
voteDown: false
|
||||
# User UA badge
|
||||
uaBadge: false
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
# 伺服器地址
|
||||
host: "0.0.0.0"
|
||||
|
||||
# 伺服器端口
|
||||
port: 23366
|
||||
|
||||
# 加密密鑰
|
||||
app_key: ""
|
||||
|
||||
# 偵錯模式
|
||||
debug: false
|
||||
|
||||
# 語言 ["en", "zh-CN", "zh-TW", "ja", "fr", "ko", "ru"]
|
||||
locale: zh-TW
|
||||
|
||||
# 時區
|
||||
timezone: Asia/Taipei
|
||||
|
||||
# 預設站點名稱
|
||||
site_default: 預設站點
|
||||
|
||||
# 預設站點地址
|
||||
site_url: ""
|
||||
|
||||
# 登入有效時長 (單位:秒)
|
||||
login_timeout: 259200
|
||||
|
||||
# 資料庫
|
||||
db:
|
||||
# 資料庫類型 ["sqlite", "mysql", "pgsql", "mssql"]
|
||||
type: sqlite
|
||||
# 資料庫文件 (僅 SQLite 資料庫需填寫)
|
||||
file: ./data/artalk.db
|
||||
# 資料庫名稱
|
||||
name: artalk
|
||||
# 資料庫地址
|
||||
host: localhost
|
||||
# 資料庫端口
|
||||
port: 3306
|
||||
# 資料庫帳號
|
||||
user: root
|
||||
# 資料庫密碼
|
||||
password: ""
|
||||
# 編碼格式
|
||||
charset: utf8mb4
|
||||
# 表前綴 (例如:"atk_")
|
||||
table_prefix: ""
|
||||
# 啟用 SSL
|
||||
ssl: false
|
||||
# 預編譯語句
|
||||
prepare_stmt: true
|
||||
|
||||
# 伺服器
|
||||
http:
|
||||
# 請求體大小限制 (單位:MB)
|
||||
body_limit: 100
|
||||
# 代理標頭名 (當使用 CDN 時填寫 `X-Forwarded-For` 獲取用戶真實 IP)
|
||||
proxy_header: ""
|
||||
|
||||
# 日誌
|
||||
log:
|
||||
# 啟用日誌
|
||||
enabled: true
|
||||
# 日誌文件路徑
|
||||
filename: ./data/artalk.log
|
||||
|
||||
# 快取
|
||||
cache:
|
||||
# 啟用快取
|
||||
enabled: false
|
||||
# 快取類型 ["redis", "memcache", "builtin"]
|
||||
type: builtin
|
||||
# 快取過期時間 (單位:分鐘)
|
||||
expires: 30
|
||||
# 快取啟動預熱 (程式啟動時預熱快取)
|
||||
warm_up: false
|
||||
# 快取伺服器地址 (例如:"localhost:6379")
|
||||
server: ""
|
||||
# Redis 配置
|
||||
redis:
|
||||
# 連接方式 ["tcp", "unix"]
|
||||
network: tcp
|
||||
# 用戶名
|
||||
username: ""
|
||||
# 密碼
|
||||
password: ""
|
||||
# 資料庫編號 (例如使用零號資料庫填寫 0)
|
||||
db: 0
|
||||
|
||||
# 可信網域
|
||||
# -- 例如:["https://artalk.example.com:23366"] --
|
||||
trusted_domains: []
|
||||
|
||||
# SSL
|
||||
ssl:
|
||||
# 啟用 SSL
|
||||
enabled: false
|
||||
# 憑證文件路徑
|
||||
cert_path: ""
|
||||
# 密鑰文件路徑
|
||||
key_path: ""
|
||||
|
||||
# 管理員帳戶
|
||||
# --
|
||||
# - name: "admin"
|
||||
# email: "admin@example.com"
|
||||
# password: "" # 支持 bcrypt 或 md5 加密,如:"(bcrypt)$2y$10$ti4vZYIrxVN8rLcYXVgXCO.GJND0dyI49r7IoF3xqIx8bBRmIBZRm"
|
||||
# badge_name: "管理員"
|
||||
# badge_color: "#0083FF"
|
||||
# --
|
||||
admin_users: []
|
||||
|
||||
# 評論審核
|
||||
moderator:
|
||||
# 預設待審 (發表新評論需要後台人工審核後才能顯示)
|
||||
pending_default: false
|
||||
# API 請求錯誤時攔截 (關閉此項當請求錯誤時讓評論放行)
|
||||
api_fail_block: false
|
||||
# Akismet Key
|
||||
# (Akismet 反垃圾服務,https://akismet.com)
|
||||
akismet_key: ""
|
||||
# 騰訊雲文本內容安全
|
||||
# (https://cloud.tencent.com/document/product/1124/64508)
|
||||
tencent:
|
||||
enabled: false
|
||||
secret_id: ""
|
||||
secret_key: ""
|
||||
region: ap-guangzhou
|
||||
# 阿里雲內容安全
|
||||
# (https://help.aliyun.com/document_detail/28417.html)
|
||||
aliyun:
|
||||
enabled: false
|
||||
access_key_id: ""
|
||||
access_key_secret: ""
|
||||
region: cn-shanghai
|
||||
# 關鍵詞過濾 (本地離線詞庫)
|
||||
keywords:
|
||||
enabled: false
|
||||
# 匹配成功設為待審狀態
|
||||
pending: false
|
||||
# 詞庫文件 (支持多個詞庫文件)
|
||||
files:
|
||||
- ./data/詞庫_1.txt
|
||||
# 詞庫文件內容分割符 (例如填寫 "\n" 文件中一行一個關鍵詞)
|
||||
file_sep: "\n"
|
||||
# 替換字符
|
||||
replace_to: x
|
||||
|
||||
# 驗證碼
|
||||
captcha:
|
||||
# 啟用驗證碼
|
||||
enabled: true
|
||||
# 總是需要驗證碼
|
||||
always: false
|
||||
# 驗證類型 ["image", "turnstile", "recaptcha", "hcaptcha", "geetest"]
|
||||
captcha_type: image
|
||||
# 激活驗證碼所需操作次數
|
||||
action_limit: 3
|
||||
# 重置操作計數器超時 (單位:s, 設為 -1 不重置)
|
||||
action_reset: 60
|
||||
# Turnstile
|
||||
# (https://www.cloudflare.com/products/turnstile/)
|
||||
turnstile:
|
||||
site_key: ""
|
||||
secret_key: ""
|
||||
# reCaptcha
|
||||
# (https://www.google.com/recaptcha/about/)
|
||||
recaptcha:
|
||||
site_key: ""
|
||||
secret_key: ""
|
||||
# hCaptcha (https://www.hcaptcha.com/)
|
||||
hcaptcha:
|
||||
site_key: ""
|
||||
secret_key: ""
|
||||
# Geetest 極驗 (https://www.geetest.com)
|
||||
geetest:
|
||||
captcha_id: ""
|
||||
captcha_key: ""
|
||||
|
||||
# IP 屬地
|
||||
ip_region:
|
||||
# 啟用 IP 屬地展示
|
||||
enabled: false
|
||||
# 數據文件路徑 (.xdb 格式)
|
||||
db_path: ./data/ip2region.xdb
|
||||
# 顯示精度 ["province", "city", "country"]
|
||||
precision: province
|
||||
|
||||
# 圖片上傳
|
||||
img_upload:
|
||||
# 啟用圖片上傳
|
||||
enabled: true
|
||||
# 圖片存放路徑
|
||||
path: ./data/artalk-img/
|
||||
# 圖片大小限制 (單位:MB)
|
||||
max_size: 5
|
||||
# 圖片連結基礎路徑 (默認為 "/static/images/")
|
||||
public_path: null
|
||||
# Upgit 配置
|
||||
# (使用 Upgit 將圖片上傳到 GitHub 或圖床:https://github.com/pluveto/upgit)
|
||||
upgit:
|
||||
# 啟用 Upgit
|
||||
enabled: false
|
||||
# 命令行參數
|
||||
exec: upgit -c <upgit配置文件路徑> -t /artalk-img
|
||||
# 上傳後刪除本地的圖片
|
||||
del_local: true
|
||||
|
||||
# 郵件通知
|
||||
email:
|
||||
# 啟用郵件通知
|
||||
enabled: false
|
||||
# 發送方式 ["smtp", "ali_dm", "sendmail"]
|
||||
send_type: smtp
|
||||
# 發信人暱稱
|
||||
send_name: "{{reply_nick}}"
|
||||
# 發信人地址
|
||||
send_addr: noreply@example.com
|
||||
# 郵件標題
|
||||
mail_subject: "[{{site_name}}] 您收到了來自 @{{reply_nick}} 的回覆"
|
||||
# 郵件模板文件 (填入文件路徑使用自定義模板)
|
||||
mail_tpl: default
|
||||
# SMTP 發送 (啟用請將發送方式設為 "smtp")
|
||||
smtp:
|
||||
# 發件地址
|
||||
host: smtp.qq.com
|
||||
# 發件端口
|
||||
port: 587
|
||||
# 用戶名
|
||||
username: example@qq.com
|
||||
# 密碼
|
||||
password: ""
|
||||
# 阿里雲郵件推送
|
||||
# (啟用請將發送方式設為 "ali_dm";參考:https://help.aliyun.com/document_detail/29444.html)
|
||||
ali_dm:
|
||||
access_key_id: ""
|
||||
access_key_secret: ""
|
||||
account_name: noreply@example.com
|
||||
|
||||
# 多元推送
|
||||
admin_notify:
|
||||
# 通知模板 (填入文件路徑使用自定義模板)
|
||||
notify_tpl: default
|
||||
# 待審評論仍然發送通知 (當評論被攔截時仍然發送通知)
|
||||
notify_pending: false
|
||||
# 嘈雜模式
|
||||
noise_mode: false
|
||||
# 郵件通知管理員
|
||||
email:
|
||||
# 開啟 (當使用其他推送方式時,可以關閉管理員郵件通知)
|
||||
enabled: true
|
||||
# 郵件標題 (發送給管理員的郵件標題)
|
||||
mail_subject: "[{{site_name}}] 您的文章「{{page_title}}」有新回覆"
|
||||
# 管理員郵件模板文件 (填入文件路徑使用自定義模板)
|
||||
mail_tpl: ""
|
||||
# Telegram
|
||||
telegram:
|
||||
enabled: false
|
||||
api_token: ""
|
||||
receivers:
|
||||
- 7777777
|
||||
# Bark
|
||||
bark:
|
||||
enabled: false
|
||||
server: http://day.app/xxxxxxx/
|
||||
# 飛書
|
||||
lark:
|
||||
enabled: false
|
||||
webhook_url: ""
|
||||
# 消息類型 ["text", "card"]
|
||||
msg_type: "text"
|
||||
# WebHook
|
||||
webhook:
|
||||
enabled: false
|
||||
url: ""
|
||||
# 釘釘
|
||||
ding_talk:
|
||||
enabled: false
|
||||
token: ""
|
||||
secret: ""
|
||||
# Slack
|
||||
slack:
|
||||
enabled: false
|
||||
oauth_token: ""
|
||||
receivers:
|
||||
- CHANNEL_ID
|
||||
# LINE
|
||||
line:
|
||||
enabled: false
|
||||
channel_secret: ""
|
||||
channel_access_token: ""
|
||||
receivers:
|
||||
- USER_ID_1
|
||||
- GROUP_ID_1
|
||||
|
||||
# 社交登錄
|
||||
auth:
|
||||
# 啟用社交登錄
|
||||
enabled: false
|
||||
# 允許匿名評論 (允許跳過驗證,僅填寫匿名的暱稱和郵箱)
|
||||
anonymous: false
|
||||
# 回調地址 (https://example.com/api/v2/auth/{provider}/callback)
|
||||
callback: "http://localhost:23366/api/v2/auth/{provider}/callback"
|
||||
# Email
|
||||
email:
|
||||
# 啟用郵箱密碼登錄
|
||||
enabled: true
|
||||
# 郵箱驗證郵件標題
|
||||
verify_subject: "您的驗證碼是 - {{code}}"
|
||||
# 郵箱驗證郵件模板 (填入文件路徑使用自定義模板)
|
||||
verify_tpl: default
|
||||
# GitHub
|
||||
github:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# GitLab
|
||||
gitlab:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Gitea
|
||||
gitea:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Google
|
||||
google:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Mastodon
|
||||
mastodon:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Twitter
|
||||
twitter:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Facebook
|
||||
facebook:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Discord
|
||||
discord:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Steam
|
||||
steam:
|
||||
enabled: false
|
||||
api_key: ""
|
||||
# Apple
|
||||
apple:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Microsoft
|
||||
microsoft:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# 微信
|
||||
wechat:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Tiktok
|
||||
tiktok:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Slack
|
||||
slack:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Line
|
||||
line:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Patreon
|
||||
patreon:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
# Auth0
|
||||
auth0:
|
||||
enabled: false
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
domain: ""
|
||||
|
||||
# 介面配置
|
||||
frontend:
|
||||
# 評論框占位文字
|
||||
placeholder: ""
|
||||
# 無評論顯示文字
|
||||
noComment: ""
|
||||
# 發送按鈕文字
|
||||
sendBtn: ""
|
||||
# 評論框穿梭
|
||||
editorTravel: true
|
||||
# 表情包
|
||||
emoticons: https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json
|
||||
# 投票按鈕
|
||||
vote: true
|
||||
# 反對按鈕
|
||||
voteDown: false
|
||||
# 用戶 UA 徽章
|
||||
uaBadge: false
|
||||
# 評論排序功能
|
||||
listSort: true
|
||||
# 編輯器實時預覽功能
|
||||
preview: true
|
||||
# 平鋪模式 ["auto", true, false]
|
||||
flatMode: auto
|
||||
# 夜間模式 ["inherit", "auto"]
|
||||
darkMode: inherit
|
||||
# 最大嵌套層數
|
||||
nestMax: 2
|
||||
# 嵌套評論排序規則 ["DATE_ASC", "DATE_DESC", "VOTE_UP_DESC"]
|
||||
nestSort: DATE_ASC
|
||||
# 頭像 Gravatar
|
||||
gravatar:
|
||||
# API 地址
|
||||
mirror: https://weavatar.com/avatar/
|
||||
# API 參數
|
||||
params: sha256=1&d=mp&s=240
|
||||
# 評論分頁
|
||||
pagination:
|
||||
# 每頁評論數
|
||||
pageSize: 20
|
||||
# 加載更多模式 (關閉則使用分頁條)
|
||||
readMore: true
|
||||
# 滾動加載
|
||||
autoLoad: true
|
||||
# 內容限高
|
||||
heightLimit:
|
||||
# 評論內容限高 (單位:px)
|
||||
content: 300
|
||||
# 子評論區域限高 (單位:px)
|
||||
children: 400
|
||||
# 滾動限高 (允許限高區域滾動)
|
||||
scrollable: false
|
||||
# 圖片懶加載 [false, "native", "data-src"]
|
||||
imgLazyLoad: false
|
||||
# 請求超時 (單位:毫秒)
|
||||
reqTimeout: 15000
|
||||
# 版本檢測
|
||||
versionCheck: true
|
||||
# 插件
|
||||
pluginURLs: []
|
||||
@@ -17,7 +17,7 @@ export const en = defineConfig({
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Core Guide',
|
||||
text: 'Basic Usage',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Sidebar', link: '/en/guide/frontend/sidebar.md' },
|
||||
@@ -32,7 +32,7 @@ export const en = defineConfig({
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Advanced Guide',
|
||||
text: 'Extensions',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Emoticons', link: '/en/guide/frontend/emoticons.md' },
|
||||
@@ -40,22 +40,23 @@ export const en = defineConfig({
|
||||
{ text: 'LaTeX', link: '/en/guide/frontend/latex.md' },
|
||||
{ text: 'Image Lightbox', link: '/en/guide/frontend/lightbox.md' },
|
||||
{ text: 'Image Lazy Load', link: '/en/guide/frontend/img-lazy-load.md' },
|
||||
{ text: 'Voting', link: '/zh/guide/frontend/voting.md' },
|
||||
{ text: 'IP Region', link: '/en/guide/frontend/ip-region.md' },
|
||||
{ text: 'Localization', link: '/en/guide/frontend/i18n.md' },
|
||||
{ text: 'Development Documentation', link: '/en/develop/index.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Configuration Documentation',
|
||||
text: 'Configurations',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Environment Variables', link: '/en/guide/env.md' },
|
||||
{ text: 'Configuration File', link: '/en/guide/backend/config.md' },
|
||||
{ text: 'Interface Configuration', link: '/en/guide/frontend/config.md' },
|
||||
{ text: 'UI Configuration', link: '/en/guide/frontend/config.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Deployment Instructions',
|
||||
text: 'Deployment details',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Daemon Process', link: '/en/guide/backend/daemon.md' },
|
||||
@@ -82,7 +83,8 @@ export const en = defineConfig({
|
||||
{ text: 'Import to Blog', link: '/en/develop/import-blog.md' },
|
||||
{ text: 'Import to Framework', link: '/en/develop/import-framework.md' },
|
||||
{ text: 'Frontend API', link: '/en/develop/fe-api.md' },
|
||||
{ text: 'Frontend Event', link: '/en/develop/event.md' },
|
||||
{ text: 'Frontend Events', link: '/en/develop/event.md' },
|
||||
{ text: 'Frontend Types', link: 'https://artalk.js.org/typedoc/' },
|
||||
{ text: 'Plugin Development', link: '/en/develop/plugin.md' },
|
||||
{ text: 'Compatibility', link: '/en/develop/compatibility.md' },
|
||||
{
|
||||
@@ -100,7 +102,7 @@ export const en = defineConfig({
|
||||
link: '/en/guide/intro',
|
||||
},
|
||||
{
|
||||
text: 'Deployment',
|
||||
text: 'Installation',
|
||||
link: '/en/guide/deploy',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
import iterator from 'markdown-it-for-inline'
|
||||
import {
|
||||
GitChangelog,
|
||||
GitChangelogMarkdownSection,
|
||||
} from '@nolebase/vitepress-plugin-git-changelog/vite'
|
||||
import * as Version from '../../code/ArtalkVersion.json'
|
||||
|
||||
export const shared = defineConfig({
|
||||
@@ -24,12 +27,18 @@ export const shared = defineConfig({
|
||||
dark: 'github-dark',
|
||||
},
|
||||
config: (md) => {
|
||||
md.use(iterator, 'artalk_version', 'text', function (tokens, idx) {
|
||||
tokens[idx].content = tokens[idx].content.replace(/:ArtalkVersion:/g, Version.latest)
|
||||
})
|
||||
md.use(iterator, 'artalk_version_link', 'link_open', (tokens, idx) => {
|
||||
const href = tokens[idx].attrGet('href')
|
||||
tokens[idx].attrSet('href', href.replace(/:ArtalkVersion:/g, Version.latest))
|
||||
const renderVersion = (c: string) => String(c).replace(/:ArtalkVersion:/g, Version.latest)
|
||||
md.core.ruler.push('artalk_version', (state) => {
|
||||
state.tokens?.forEach((token) => {
|
||||
if (token.type === 'inline') {
|
||||
token.children?.forEach((child) => {
|
||||
if (['text', 'link_open', 'code_inline'].includes(child.type))
|
||||
child.content = renderVersion(child.content)
|
||||
})
|
||||
} else if (token.type === 'fence') {
|
||||
token.content = renderVersion(token.content)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -62,5 +71,28 @@ export const shared = defineConfig({
|
||||
server: {
|
||||
open: '/zh/guide/intro.html',
|
||||
},
|
||||
plugins: [
|
||||
GitChangelog({
|
||||
repoURL: () => 'https://github.com/ArtalkJS/Artalk',
|
||||
mapAuthors: [
|
||||
{
|
||||
name: 'qwqcode',
|
||||
username: 'qwqcode',
|
||||
mapByEmailAliases: ['qwqcode@gmail.com', '22412567+qwqcode@users.noreply.github.com'],
|
||||
},
|
||||
{
|
||||
name: 'pluveto',
|
||||
username: 'pluveto',
|
||||
mapByEmailAliases: ['i@pluvet.com', '50045289+pluveto@users.noreply.github.com'],
|
||||
},
|
||||
{
|
||||
name: 'Mr.Hope',
|
||||
username: 'Mister-Hope',
|
||||
mapByEmailAliases: ['mister-hope@outlook.com'],
|
||||
},
|
||||
],
|
||||
}),
|
||||
GitChangelogMarkdownSection(),
|
||||
],
|
||||
},
|
||||
})
|
||||
@@ -40,6 +40,7 @@ export const zh = defineConfig({
|
||||
{ text: 'LaTeX', link: '/zh/guide/frontend/latex.md' },
|
||||
{ text: '图片灯箱', link: '/zh/guide/frontend/lightbox.md' },
|
||||
{ text: '图片懒加载', link: '/zh/guide/frontend/img-lazy-load.md' },
|
||||
{ text: '投票功能', link: '/zh/guide/frontend/voting.md' },
|
||||
{ text: 'IP 属地', link: '/zh/guide/frontend/ip-region.md' },
|
||||
{ text: '多语言', link: '/zh/guide/frontend/i18n.md' },
|
||||
{ text: '开发文档', link: '/zh/develop/index.md' },
|
||||
@@ -85,7 +86,8 @@ export const zh = defineConfig({
|
||||
{ text: '置入博客', link: '/zh/develop/import-blog.md' },
|
||||
{ text: '置入框架', link: '/zh/develop/import-framework.md' },
|
||||
{ text: '前端 API', link: '/zh/develop/fe-api.md' },
|
||||
{ text: '前端 Event', link: '/zh/develop/event.md' },
|
||||
{ text: '前端 Events', link: '/zh/develop/event.md' },
|
||||
{ text: '前端 Types', link: 'https://artalk.js.org/typedoc/' },
|
||||
{ text: '插件开发', link: '/zh/develop/plugin.md' },
|
||||
{ text: '兼容性', link: '/zh/develop/compatibility.md' },
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ArtalkKatexPlugin } from '@artalk/plugin-katex'
|
||||
import { ArtalkLightboxPlugin } from '@artalk/plugin-lightbox'
|
||||
import 'lightgallery/css/lightgallery.css'
|
||||
import 'katex/dist/katex.min.css'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
const el = ref<HTMLElement | null>(null)
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import { Theme } from 'vitepress'
|
||||
import { NolebaseGitChangelogPlugin } from '@nolebase/vitepress-plugin-git-changelog/client'
|
||||
import Layout from './Layout.vue'
|
||||
import Artalk from './Artalk.vue'
|
||||
import Artransfer from './Artransfer.vue'
|
||||
|
||||
import '@nolebase/vitepress-plugin-git-changelog/client/style.css'
|
||||
|
||||
export default {
|
||||
...DefaultTheme,
|
||||
|
||||
@@ -12,6 +15,7 @@ export default {
|
||||
enhanceApp({ app, router, siteData }) {
|
||||
app.component('Artransfer', Artransfer)
|
||||
app.component('Artalk', Artalk)
|
||||
app.use(NolebaseGitChangelogPlugin)
|
||||
|
||||
// app is the Vue 3 app instance from `createApp()`.
|
||||
// router is VitePress' custom router. `siteData` is
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Frontend API
|
||||
|
||||
Here are some of the main Artalk client APIs for operating the Artalk instance in frontend code.
|
||||
|
||||
For more detailed API information, you can browse the [TypeDoc documentation](https://artalk.js.org/typedoc/).
|
||||
|
||||
## Install Dependencies
|
||||
|
||||
Use your preferred package manager to install Artalk:
|
||||
|
||||
@@ -17,7 +17,7 @@ pnpm add artalk
|
||||
import Artalk from 'artalk'
|
||||
import { onMounted, onBeforeUnmount, ref } from 'vue'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
const el = ref<HTMLElement>()
|
||||
|
||||
@@ -50,7 +50,7 @@ import Artalk from 'artalk'
|
||||
import { onMounted, onBeforeUnmount, ref, watch, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
const el = ref<HTMLElement>()
|
||||
const router = useRouter()
|
||||
@@ -98,32 +98,37 @@ onBeforeUnmount(() => {
|
||||
::: code-group
|
||||
|
||||
```tsx [React Hooks]
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { useCallback, useRef } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
import Artalk from 'artalk'
|
||||
|
||||
const ArtalkComment = () => {
|
||||
const container = useRef<HTMLDivElement>(null)
|
||||
const location = useLocation()
|
||||
const { pathname } = useLocation()
|
||||
const artalk = useRef<Artalk>()
|
||||
|
||||
useEffect(() => {
|
||||
artalk.current = Artalk.init({
|
||||
el: container.current!,
|
||||
pageKey: location.pathname,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk Blog',
|
||||
// ...
|
||||
})
|
||||
const handleContainerInit = useCallback(
|
||||
(node: HTMLDivElement | null) => {
|
||||
if (!node) {
|
||||
return
|
||||
}
|
||||
if (artalk.current) {
|
||||
artalk.current.destroy()
|
||||
artalk.current = undefined
|
||||
}
|
||||
artalk.current = Artalk.init({
|
||||
el: node,
|
||||
pageKey: pathname,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk Blog',
|
||||
// ...
|
||||
})
|
||||
},
|
||||
[pathname],
|
||||
)
|
||||
|
||||
return () => {
|
||||
artalk.current?.destroy()
|
||||
}
|
||||
}, [location.pathname])
|
||||
|
||||
return <div ref={container}></div>
|
||||
return <div ref={handleContainerInit}></div>
|
||||
}
|
||||
|
||||
export default ArtalkComment
|
||||
@@ -131,7 +136,7 @@ export default ArtalkComment
|
||||
|
||||
```jsx [React Class]
|
||||
import React, { createRef } from 'react'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
import Artalk from 'artalk'
|
||||
|
||||
export default class ArtalkComponent extends React.Component {
|
||||
@@ -166,7 +171,7 @@ export default class ArtalkComponent extends React.Component {
|
||||
```tsx
|
||||
import { onCleanup, onMount } from 'solid-js'
|
||||
import Artalk from 'artalk'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
const ArtalkComment = () => {
|
||||
let el: HTMLDivElement
|
||||
@@ -198,7 +203,7 @@ const ArtalkComment = () => {
|
||||
import Artalk from 'artalk'
|
||||
import { onMount, onDestroy } from 'svelte'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
let el
|
||||
let artalk
|
||||
|
||||
@@ -12,8 +12,9 @@ Thank you for your interest and support of Artalk. We deeply understand that the
|
||||
|
||||
- [Embed in Blog](./import-blog.md)
|
||||
- [Embed in Framework](./import-framework.md)
|
||||
- [Frontend API Documentation](./fe-api.md)
|
||||
- [Frontend API](./fe-api.md)
|
||||
- [Frontend Events](./event.md)
|
||||
- [Frontend Types](https://artalk.js.org/typedoc/)
|
||||
- [Frontend Configuration](../guide/frontend/config.md)
|
||||
|
||||
**Plugin Development**
|
||||
|
||||
@@ -47,11 +47,11 @@ Import the embedded client JS and CSS resources from the Artalk server to your w
|
||||
<div id="Comments"></div>
|
||||
<script>
|
||||
Artalk.init({
|
||||
el: '#Comments', // Selector of the bound element
|
||||
pageKey: '/post/1', // Permalink
|
||||
pageTitle: 'About Introducing Artalk', // Page title (leave blank to auto-fetch)
|
||||
el: '#Comments', // Selector of the bound element
|
||||
pageKey: '/post/1', // Permalink
|
||||
pageTitle: 'About Introducing Artalk', // Page title (leave blank to auto-fetch)
|
||||
server: 'http://artalk.example.com:8080', // Artalk server address
|
||||
site: 'Artalk Blog', // Your site name
|
||||
site: 'Artalk Blog', // Your site name
|
||||
})
|
||||
</script>
|
||||
```
|
||||
@@ -79,7 +79,7 @@ Advanced operations:
|
||||
- [Reverse Proxy (Caddy, Nginx, Apache)](./backend/reverse-proxy.md)
|
||||
- [Self-compile (Build from the latest code)](https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md)
|
||||
|
||||
## Go Module
|
||||
## Go Install
|
||||
|
||||
If you have the Golang toolchain installed, you can run the following commands to compile and install the latest version of Artalk:
|
||||
|
||||
@@ -97,6 +97,14 @@ The client integration steps are [here](#integrate-client).
|
||||
|
||||
## Linux Distributions
|
||||
|
||||
**Fedora (Copr)**:
|
||||
|
||||
```bash
|
||||
dnf install 'dnf-command(copr)'
|
||||
dnf copr enable @artalk/artalk
|
||||
dnf install artalk
|
||||
```
|
||||
|
||||
**Arch Linux (AUR)**:
|
||||
|
||||
```bash
|
||||
@@ -117,6 +125,8 @@ pkg install artalk
|
||||
|
||||
[](https://repology.org/project/artalk/versions)
|
||||
|
||||
[](https://copr.fedorainfracloud.org/coprs/g/artalk/artalk/)
|
||||
|
||||
## Docker Compose
|
||||
|
||||
Create a working directory and edit the `docker-compose.yml` file:
|
||||
@@ -161,26 +171,50 @@ docker-compose exec artalk bash # Enter the container
|
||||
|
||||
More information: [Docker](./backend/docker.md) / [Environment Variables](./env.md)
|
||||
|
||||
## Client Projects (Node.js)
|
||||
## Client
|
||||
|
||||
Install Artalk via npm:
|
||||
If you have a frontend or Node.js web project, this following guide will help you integrate the Artalk **Client** into your web project.
|
||||
|
||||
```bash
|
||||
### Client Installation
|
||||
|
||||
Install via npm:
|
||||
|
||||
::: code-group
|
||||
|
||||
```sh [npm]
|
||||
npm install artalk
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add artalk
|
||||
```
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm add artalk
|
||||
```
|
||||
|
||||
```sh [bun]
|
||||
bun add artalk
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
(or see [CDN Resources](#client-cdn-resources)).
|
||||
|
||||
### Client Usage
|
||||
|
||||
Import Artalk in your web project:
|
||||
|
||||
```js
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
import Artalk from 'artalk'
|
||||
|
||||
const artalk = Artalk.init({
|
||||
el: '#Comments', // Selector of the bound element
|
||||
pageKey: '/post/1', // Permalink
|
||||
pageTitle: 'About Introducing Artalk', // Page title (leave blank to auto-fetch)
|
||||
server: 'http://artalk.example.com:8080', // Artalk server address
|
||||
site: 'Artalk Blog', // Your site name
|
||||
el: document.querySelector('#Comments'), // DOM element where you want to mount
|
||||
pageKey: '/post/1', // Permalink
|
||||
pageTitle: 'About Introducing Artalk', // Page title
|
||||
server: 'http://artalk.example.com:8080', // Artalk server address
|
||||
site: 'Artalk Blog', // Site name
|
||||
})
|
||||
```
|
||||
|
||||
@@ -189,38 +223,89 @@ For more references:
|
||||
- [Import to Blog Documentation](../develop/import-blog.md)
|
||||
- [Import to Frameworks Documentation](../develop/import-framework.md)
|
||||
- [Client API Reference](../develop/fe-api.md)
|
||||
- [Client Configuration](./frontend/config.md)
|
||||
- [UI (Client) Configuration](./frontend/config.md)
|
||||
|
||||
## Client CDN Resources
|
||||
### Client CDN Resources
|
||||
|
||||
To use Artalk in the browser via CDN, for modern browsers (which support [ES modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)), you can use [esm.sh](https://esm.sh) or [esm.run](https://esm.run):
|
||||
|
||||
::: code-group
|
||||
|
||||
```html [ES Module]
|
||||
<body>
|
||||
<div id="Comments"></div>
|
||||
|
||||
<script type="module">
|
||||
import Artalk from 'https://esm.sh/artalk@:ArtalkVersion:'
|
||||
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
```html [Legacy]
|
||||
<body>
|
||||
<div id="Comments"></div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.js"></script>
|
||||
<script>
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Don't forget to include the CSS file:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.css">
|
||||
```
|
||||
|
||||
::: tip Latest Version of Artalk
|
||||
|
||||
The current latest version number of the Artalk client is: **:ArtalkVersion:**
|
||||
The latest Artalk client version is: `:ArtalkVersion:`
|
||||
|
||||
To upgrade the client, replace the numeric part of the version number in the URL.
|
||||
:::
|
||||
|
||||
The Artalk server had embedded the client resources. Ensure version compatibility when using public CDN resources.
|
||||
Note: The Artalk server had embedded the client resources. Ensure version compatibility when using public CDN resources.
|
||||
|
||||
::: details Alternative CDNs
|
||||
|
||||
**CDNJS**
|
||||
|
||||
> <https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.js>
|
||||
>
|
||||
> <https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.css>
|
||||
```
|
||||
https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.js
|
||||
```
|
||||
|
||||
::: details View More
|
||||
|
||||
**UNPKG**
|
||||
|
||||
> <https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.js>
|
||||
>
|
||||
> <https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.css>
|
||||
```
|
||||
https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.css
|
||||
```
|
||||
|
||||
**JSDELIVR**
|
||||
|
||||
> <https://cdn.jsdelivr.net/npm/artalk@:ArtalkVersion:/dist/Artalk.js>
|
||||
>
|
||||
> <https://cdn.jsdelivr.net/npm/artalk@:ArtalkVersion:/dist/Artalk.css>
|
||||
```
|
||||
https://cdn.jsdelivr.net/npm/artalk@:ArtalkVersion:/dist/Artalk.js
|
||||
```
|
||||
|
||||
```
|
||||
https://cdn.jsdelivr.net/npm/artalk@:ArtalkVersion:/dist/Artalk.css
|
||||
```
|
||||
|
||||
**UNPKG**
|
||||
|
||||
```
|
||||
https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.js
|
||||
```
|
||||
|
||||
```
|
||||
https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.css
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ ATK_TRUSTED_DOMAINS_0="https://a.com"
|
||||
| **ATK_FRONTEND_UABADGE** | `false` | User UA badge | frontend.uaBadge (UI Settings > User UA badge) |
|
||||
| **ATK_FRONTEND_VERSIONCHECK** | `true` | Version check | frontend.versionCheck (UI Settings > Version check) |
|
||||
| **ATK_FRONTEND_VOTE** | `true` | Vote button | frontend.vote (UI Settings > Vote button) |
|
||||
| **ATK_FRONTEND_VOTEDOWN** | `false` | Dislike button | frontend.voteDown (UI Settings > Dislike button) |
|
||||
| **ATK_FRONTEND_VOTEDOWN** | `false` | Vote down button | frontend.voteDown (UI Settings > Vote down button) |
|
||||
|
||||
|
||||
## Web server
|
||||
|
||||
@@ -8,6 +8,10 @@ ArtalkLite is a simplified version of Artalk, with the following differences com
|
||||
|
||||
ArtalkLite is released alongside the standard version. You can obtain it by modifying the file name in the CDN address to ArtalkLite:
|
||||
|
||||
> https://unpkg.com/artalk@2/dist/ArtalkLite.js
|
||||
>
|
||||
> https://unpkg.com/artalk@2/dist/ArtalkLite.css
|
||||
```
|
||||
https://unpkg.com/artalk@:ArtalkVersion:/dist/ArtalkLite.js
|
||||
```
|
||||
|
||||
```
|
||||
https://unpkg.com/artalk@:ArtalkVersion:/dist/ArtalkLite.css
|
||||
```
|
||||
@@ -1,16 +1,20 @@
|
||||
# Interface Configuration
|
||||
# UI Configuration
|
||||
|
||||
You can modify the interface configuration in the "[Dashboard](./sidebar.md)" without changing the front-end code. Additionally, configuration files and environment variables are also supported.
|
||||
UI configuration also known as Client (Frontend) configuration, is the configuration of the Artalk interface.
|
||||
|
||||
The priority of interface configuration is as follows:
|
||||
You can modify the UI configuration in the "[Dashboard](./sidebar.md#dashboard)" without changing the frontend code. Additionally, [Configuration files](../backend/config.md#frontend-configuration-frontend) and [Environment variables](../env.md#ui-settings) are also supported.
|
||||
|
||||
The priority of UI configuration is as follows:
|
||||
|
||||
```
|
||||
Environment Variables > Configuration File = Dashboard > Front-end Code
|
||||
Frontend Code > Environment Variables > Dashboard = Configuration File
|
||||
```
|
||||
|
||||
If you have modified the UI configuration through environment variables, configuration files, or the Dashboard, but the changes are not taking effect, please consider the issue of UI configuration priority.
|
||||
|
||||
## Configuring the Interface via `Artalk.init`
|
||||
|
||||
When initializing with `Artalk.init` on the front-end page, pass parameters to configure the interface. Below are all the available configuration options.
|
||||
When initializing with `Artalk.init` on the frontend page, pass parameters to configure the interface. Below are all the available configuration options.
|
||||
|
||||
```js
|
||||
const artalk = Artalk.init({
|
||||
@@ -81,14 +85,20 @@ Deploy the backend and ensure that the backend address is accessible from the fr
|
||||
|
||||
Artalk supports unified management of multiple sites, this item is used for site isolation.
|
||||
|
||||
### useBackendConf
|
||||
### preferRemoteConf
|
||||
|
||||
**Refer to Backend Configuration**
|
||||
**Prefer Remote Configuration**
|
||||
|
||||
- Type: `Boolean`
|
||||
- Default: `true` (enabled by default)
|
||||
- Default: `false` (disabled by default)
|
||||
|
||||
You can define the front-end configuration in the backend configuration file, so that the front-end configuration always refers to the backend.
|
||||
This config option is disabled by default, meaning Artalk will prioritize using local config. Local config refers to the settings passed through `Artalk.init` in the frontend code.
|
||||
|
||||
When enabled, Artalk will prioritize using remote config. If the remote config does not exist, it will resort to using the local config. Remote config refers to the settings returned by the backend server program, allowing for dynamic config of the Artalk client. You can modify the user interface config in the "[Dashboard](./sidebar.md#dashboard)".
|
||||
|
||||
::: warning Update Notice
|
||||
As of version v2.10.0, the `useBackendConf` configuration option has been deprecated and is always `true`. Please use `preferRemoteConf` instead.
|
||||
:::
|
||||
|
||||
## Internationalization (i18n)
|
||||
|
||||
@@ -278,6 +288,17 @@ When querying comment counts and page views, Artalk's statistical component uses
|
||||
|
||||
To facilitate theme adaptation, you can customize the attribute name as needed, for example, replacing it with `data-path`, the HTML tag would be `<span data-path="/t/1.html"></span>`.
|
||||
|
||||
### pageVote
|
||||
|
||||
**Page Voting Buttons**
|
||||
|
||||
- Type: `Boolean | { upBtnEl: string; downBtnEl: string; upCountEl: string; downCountEl: string; activeClass: string }`
|
||||
- Default: `true`
|
||||
|
||||
Enable the page voting feature (upvote / downvote).
|
||||
|
||||
For details, see: [Page Voting](./voting.md#page-voting)
|
||||
|
||||
### vote
|
||||
|
||||
**Voting Buttons**
|
||||
@@ -517,4 +538,4 @@ Allow height limit area to scroll.
|
||||
- Type: `Boolean`
|
||||
- Default: `true`
|
||||
|
||||
Display a warning prompt when the front-end and back-end versions are incompatible.
|
||||
Display a warning prompt when the frontend and backend versions are incompatible.
|
||||
@@ -26,11 +26,12 @@ We welcome PRs to help translate Artalk into multiple languages and contribute t
|
||||
|
||||
| Translation Content | Language File Directory | Template File |
|
||||
| ------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| Backend Program | [/i18n/[LANG].yml](https://github.com/ArtalkJS/Artalk/tree/master/i18n) | [zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/i18n/zh-CN.yml) |
|
||||
| Frontend Interface | [/ui/artalk/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk/src/i18n) | [zh-CN.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/i18n/zh-CN.ts) |
|
||||
| Backend Interface | [/ui/artalk-sidebar/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk-sidebar/src/i18n) | [zh-CN.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk-sidebar/src/i18n/zh-CN.ts) |
|
||||
| Configuration Files | [/conf/artalk.example.[LANG].yml](https://github.com/ArtalkJS/Artalk/tree/master/conf) | [artalk.example.zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/conf/artalk.example.zh-CN.yml) |
|
||||
| Documentation | [/docs/[LANG]/\*\*/\*.md](https://github.com/ArtalkJS/Artalk/tree/master/docs) | [/docs/zh/\*\*/\*.md](https://github.com/ArtalkJS/Artalk/tree/master/docs) |
|
||||
| Backend Program | [/i18n/[LANG].yml](https://github.com/ArtalkJS/Artalk/tree/master/i18n) | [en.yml](https://github.com/ArtalkJS/Artalk/blob/master/i18n/en.yml) |
|
||||
| Frontend Interface | [/ui/artalk/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk/src/i18n) | [en.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/i18n/en.ts) |
|
||||
| Backend Interface | [/ui/artalk-sidebar/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk-sidebar/src/i18n) | [i18n-en.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk-sidebar/src/i18n-en.ts) |
|
||||
| Configuration Files | [/conf/artalk.example.[LANG].yml](https://github.com/ArtalkJS/Artalk/tree/master/conf) | [artalk.example.yml](https://github.com/ArtalkJS/Artalk/blob/master/conf/artalk.example.yml) |
|
||||
| Documentation | [/docs/docs/[LANG]/\*\*/\*.md](https://github.com/ArtalkJS/Artalk/tree/master/docs/docs) | [en/\*\*/\*.md](https://github.com/ArtalkJS/Artalk/tree/master/docs/docs/en) |
|
||||
| Official website home page | [/docs/landing/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/tree/master/docs/landing/src/i18n) | [en.ts](https://github.com/ArtalkJS/Artalk/blob/master/docs/landing/src/i18n/en.ts) |
|
||||
|
||||
For more details, refer to: [Development Documentation](../../develop/index.md) / [CONTRIBUTING.md](https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md#translation)
|
||||
|
||||
@@ -58,7 +59,7 @@ Artalk.init({
|
||||
|
||||
### Custom Frontend Locale Content
|
||||
|
||||
You can pass an Object type to the frontend and customize the locale content according to the keys in the [template file](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/i18n/zh-CN.ts).
|
||||
You can pass an Object type to the frontend and customize the locale content according to the keys in the [template file](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/i18n/en.ts).
|
||||
|
||||
```js
|
||||
Artalk.init({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Image Lazy Loading
|
||||
|
||||
Artalk supports adding lazy loading functionality to images within comments to reduce page load times. This feature is disabled by default. You can find the "Image Lazy Load" configuration item (frontend.imgLazyLoad) in the Dashboard under "Settings - Interface Configuration":
|
||||
Artalk supports adding lazy loading functionality to images within comments to reduce page load times. This feature is disabled by default. You can find the "Image Lazy Load" configuration item (frontend.imgLazyLoad) in the Dashboard under "Settings - UI Configuration":
|
||||
|
||||
| Configuration Value | Description |
|
||||
| --- | --- |
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# Voting Feature
|
||||
|
||||
Artalk supports voting on comments and pages, allowing users to click the "Up" or "Down" buttons to cast their votes. The comment list can be sorted based on the number of votes, which helps users better assess the quality of the comments.
|
||||
|
||||
## Comment Voting
|
||||
|
||||
The comment voting feature is enabled by default, allowing users to vote on comments.
|
||||
|
||||
You can find the "UI Settings" in the Dashboard to modify the "Vote Button" option to enable or disable comment voting.
|
||||
|
||||
Environment variable for the vote button:
|
||||
|
||||
```
|
||||
ATK_FRONTEND_VOTE=1
|
||||
```
|
||||
|
||||
Configuration file for the vote button:
|
||||
|
||||
```yaml
|
||||
frontend:
|
||||
vote: true
|
||||
```
|
||||
|
||||
### Down Button
|
||||
|
||||
By default, Artalk does not display the Down button. You can find the "UI Settings" in the Dashboard to modify the "Vote Down Button" option to enable it.
|
||||
|
||||
Environment variable for the Down button:
|
||||
|
||||
```
|
||||
ATK_FRONTEND_VOTE_DOWN=1
|
||||
```
|
||||
|
||||
Configuration file for the Down button:
|
||||
|
||||
```yaml
|
||||
frontend:
|
||||
voteDown: true
|
||||
```
|
||||
|
||||
## Page Voting
|
||||
|
||||
Artalk supports voting on pages. To enable page voting, you need to add elements in the page to display the voting buttons, which Artalk will automatically initialize on load:
|
||||
|
||||
```html
|
||||
<div>
|
||||
<span class="artalk-page-vote-up"></span>
|
||||
<span class="artalk-page-vote-down"></span>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Voted Status Styling
|
||||
|
||||
When users click the page voting button, the element will be given an `active` class to indicate that the user has voted. For example:
|
||||
|
||||
```html
|
||||
<span class="artalk-page-vote-up active"></span>
|
||||
```
|
||||
|
||||
You can customize the voted button style using CSS:
|
||||
|
||||
```css
|
||||
.artalk-page-vote-up.active {
|
||||
color: #0083ff;
|
||||
}
|
||||
```
|
||||
|
||||
The default added class name is `active`, but it can be changed using `pageVote.activeClass` in the client configuration:
|
||||
|
||||
```js
|
||||
Artalk.init({
|
||||
pageVote: {
|
||||
activeClass: 'active',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Custom Element Selectors
|
||||
|
||||
By default, Artalk searches for `.artalk-page-vote-up` and `.artalk-page-vote-down` as the voting button elements.
|
||||
|
||||
You can customize the voting button selectors by modifying the `pageVote.upBtnEl` and `pageVote.downBtnEl` configuration in the client:
|
||||
|
||||
```js
|
||||
Artalk.init({
|
||||
pageVote: {
|
||||
upBtnEl: '.artalk-page-vote-up',
|
||||
downBtnEl: '.artalk-page-vote-down',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Further Customizing Page Voting Buttons
|
||||
|
||||
If the voting buttons do not contain any child elements, Artalk will output the text "Up (n)" into the element.
|
||||
|
||||
If you want to output the vote count into a separate element, you can add a tag inside the button, for example:
|
||||
|
||||
```html
|
||||
<div class="artalk-page-vote">
|
||||
<span class="artalk-page-vote-up">
|
||||
👍 (<span class="artalk-page-vote-up-count"></span>)
|
||||
</span>
|
||||
<span class="artalk-page-vote-down">
|
||||
👎 (<span class="artalk-page-vote-down-count"></span>)
|
||||
</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
To further customize, you can replace the text with icons or add other styles.
|
||||
|
||||
The default selectors for vote counts are `.artalk-page-vote-up-count` and `.artalk-page-vote-down-count`.
|
||||
|
||||
You can modify `pageVote.upCountEl` and `pageVote.downCountEl` to customize the vote count output elements:
|
||||
|
||||
```js
|
||||
Artalk.init({
|
||||
pageVote: {
|
||||
upCountEl: '.artalk-page-vote-up-count',
|
||||
downCountEl: '.artalk-page-vote-down-count',
|
||||
},
|
||||
})
|
||||
```
|
||||
@@ -15,15 +15,13 @@
|
||||
"serve:docs": "vitepress serve"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@artalk/plugin-katex": "^0.2.4",
|
||||
"@artalk/plugin-lightbox": "^0.2.4",
|
||||
"@nolebase/vitepress-plugin-git-changelog": "^2.6.1",
|
||||
"artalk": "workspace:^",
|
||||
"markdown-it-for-inline": "^2.0.1",
|
||||
"vitepress": "1.3.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@artalk/plugin-katex": "^0.2.3",
|
||||
"@artalk/plugin-lightbox": "^0.2.3",
|
||||
"katex": "^0.16.11",
|
||||
"lightgallery": "^2.7.2",
|
||||
"vue": "^3.5.6"
|
||||
"vitepress": "1.4.1",
|
||||
"vue": "^3.5.12"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,17 @@
|
||||
/guide/frontend/import-blog.html /develop/import-blog.html 301
|
||||
/guide/frontend/import-framework.html /develop/import-framework.html 301
|
||||
/guide/frontend/install.html /guide/deploy.html 301
|
||||
/guide/backend/data.html /guide/transfer.html 301
|
||||
/guide/backend/build.html /develop/contributing.html 301
|
||||
/guide/backend/fe-control.html /guide/frontend/config.html 301
|
||||
/guide/backend/install.html /guide/deploy.html 301
|
||||
/develop/api.html /http-api.html 301
|
||||
/develop/plugs.md /develop/plugin.html 301
|
||||
|
||||
# Language redirect
|
||||
/guide/* /zh/guide/:splat 302 Language=zh
|
||||
/guide/* /en/guide/:splat 302 Language=en
|
||||
/guide/* /en/guide/:splat 302
|
||||
|
||||
/develop/* /zh/develop/:splat 302 Language=zh
|
||||
/develop/* /en/develop/:splat 302 Language=en
|
||||
/develop/* /en/develop/:splat 302
|
||||
@@ -2,7 +2,10 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"types": ["vite/client"],
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler"
|
||||
},
|
||||
"include": ["**/.vitepress/**/*"]
|
||||
"include": ["**/.vitepress/**/*.ts", "**/.vitepress/**/*.mts", "**/.vitepress/**/*.vue"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -1,592 +0,0 @@
|
||||
# HTTP API
|
||||
|
||||
::: warning
|
||||
该 HTTP API 文档已过时
|
||||
:::
|
||||
|
||||
::: tip 无特殊说明时 API 调用响应格式
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
| --------- | ------- | --------------------------------------------- |
|
||||
| `success` | Boolean | 接口调用结果 |
|
||||
| `msg` | String | 返回消息,出错时此字段包含错误消息 |
|
||||
| `data` | Any | 返回数据,可能为 Object / String / Array 类型 |
|
||||
|
||||
:::
|
||||
|
||||
## Normal API
|
||||
|
||||
### 评论新增
|
||||
|
||||
**POST** `/api/add`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------------ | -------- | :--: | ------------------------------------------------- |
|
||||
| `name` | String | 是 | 待新增评论者昵称 |
|
||||
| `email` | String | 是 | 待新增评论者邮箱 |
|
||||
| `link` | String | 否 | 待新增评论者链接 |
|
||||
| `content` | String | 是 | 待新增评论内容 |
|
||||
| `rid` | Number | 否 | 待新增评论为回复评论时传入父评论 `ID`,否则为 `0` |
|
||||
| `page_key` | String | 是 | 待新增评论目标页面唯一标识符 |
|
||||
| `page_title` | String | 否 | 待新增评论目标页面标题 |
|
||||
| `token` | String | 否 | 评论请求 Token |
|
||||
| `site_name` | String | 否 | 待新增评论目标站点名称 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ------------------------------ | -------- | :----: | -------------------------------------- |
|
||||
| `success` | Boolean | `true` | 评论新增成功 |
|
||||
| `data.comment` | Object | - | 评论数据 |
|
||||
| `data.comment.id` | Number | - | 评论 ID |
|
||||
| `data.comment.content` | String | - | 评论正文 |
|
||||
| `data.comment.nick` | String | - | 评论者昵称 |
|
||||
| `data.comment.email_encrypted` | String | - | 评论者邮箱 SHA256 加密值 |
|
||||
| `data.comment.link` | String | - | 评论者链接 |
|
||||
| `data.comment.ua` | String | - | 评论者 User-Agent |
|
||||
| `data.comment.date` | String | - | 评论时间,格式为 `1970-01-01 00:00:00` |
|
||||
| `data.comment.is_collapsed` | Boolean | - | 评论是否折叠 |
|
||||
| `data.comment.is_pending` | Boolean | - | 评论是否待审 |
|
||||
| `data.comment.is_allow_reply` | Boolean | - | 评论是否允许回复 |
|
||||
| `data.comment.rid` | Number | `0` | 待新增评论为回复评论时返回父评论 `ID` |
|
||||
| `data.comment.badge_name` | String | - | 评论者徽章文字 |
|
||||
| `data.comment.badge_color` | String | - | 评论者徽章颜色 |
|
||||
| `data.comment.visible` | Boolean | `true` | 评论是否可见 |
|
||||
| `data.comment.vote_up` | Number | `0` | 评论赞同数 |
|
||||
| `data.comment.vote_down` | Number | `0` | 评论反对数 |
|
||||
| `data.comment.page_key` | String | - | 评论所在页面唯一标识符 |
|
||||
| `data.comment.site_name` | String | - | 评论所在站点名称 |
|
||||
|
||||
### 评论获取
|
||||
|
||||
**POST** `/api/get`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ----------- | -------- | :--: | -------------------------- |
|
||||
| `page_key` | String | 是 | 待获取评论页面的唯一标识符 |
|
||||
| `limit` | Number | 否 | 待获取评论的数量限制 |
|
||||
| `offset` | Number | 否 | 待获取评论的起始位置偏移 |
|
||||
| `type` | String | 否 | 获取指定类型的评论 |
|
||||
| `name` | String | 否 | 获取指定昵称的评论 |
|
||||
| `email` | String | 否 | 获取指定邮箱的评论 |
|
||||
| `site_name` | String | 否 | 获取指定站点名称的评论 |
|
||||
| `flat_mode` | Boolean | 否 | 待获取评论是否平铺模式 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ---------------------- | -------- | :----: | ------------------------------ |
|
||||
| `success` | Boolean | `true` | 评论获取成功 |
|
||||
| `data.comments` | Array | - | 页面评论数据 |
|
||||
| `data.total` | Number | - | 页面评论总数(包括所有子评论) |
|
||||
| `data.total_parents` | Number | - | 页面评论中父级评论总数 |
|
||||
| `data.page` | Object | - | 页面数据 |
|
||||
| `data.page.id` | Number | - | 页面 ID |
|
||||
| `data.page.admin_only` | Boolean | - | 页面是否仅管理员可评论 |
|
||||
| `data.page.key` | String | - | 页面唯一标识符 |
|
||||
| `data.page.url` | String | - | 页面链接 |
|
||||
| `data.page.title` | String | - | 页面标题 |
|
||||
| `data.page.site_name` | String | - | 页面所在站点名称 |
|
||||
| `data.page.vote_up` | Number | - | 页面赞同数 |
|
||||
| `data.page.vote_down` | Number | - | 页面反对数 |
|
||||
| `data.unread` | Array | - | 未读的评论提醒数据 |
|
||||
| `data.unread_count` | Number | - | 未读的评论提醒数据总数 |
|
||||
| `data.api_version` | Object | - | 目标 Artalk 后端版本数据 |
|
||||
|
||||
::: tip
|
||||
|
||||
- `data.comments` 数组中元素结构参考 [评论新增接口](#评论新增) `/api/add` 响应的 `data.comment`
|
||||
- `data.unread` 数组中元素结构如下
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ----- | ------- | :-: | --- |
|
||||
| `id` | Number | - | 评论提醒 ID |
|
||||
| `user_id` | Number | - | 评论提醒目标用户 ID |
|
||||
| `comment_id` | Number | - | 评论提醒来源评论 ID |
|
||||
| `is_read` | Boolean | - | 评论提醒是否已读 |
|
||||
| `is_emailed` | Boolean | - | 评论提醒是否已发送邮件 |
|
||||
| `read_link` | String | - | 评论提醒已读地址 |
|
||||
- `data.api_version` 对象结构参考 [Artalk 版本接口](#artalk-版本) `/api/version` 响应
|
||||
|
||||
:::
|
||||
|
||||
### 用户获取
|
||||
|
||||
**POST** `/api/user-get`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------- | -------- | :--: | ---------------- |
|
||||
| `name` | String | 否 | 待获取用户的昵称 |
|
||||
| `email` | String | 否 | 待获取用户的邮箱 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ----------------------- | -------- | :----: | ---------------------------------- |
|
||||
| `success` | Boolean | `true` | 用户获取成功 |
|
||||
| `data.user` | Object | `null` | 获取的用户数据,若用户不存在返回空 |
|
||||
| `data.user.id` | Number | - | 用户 ID |
|
||||
| `data.user.name` | String | - | 用户昵称 |
|
||||
| `data.user.email` | String | - | 用户邮箱 |
|
||||
| `data.user.link` | String | - | 用户链接 |
|
||||
| `data.user.badge_name` | String | - | 用户徽章文字 |
|
||||
| `data.user.badge_color` | String | - | 用户徽章颜色 |
|
||||
| `data.user.is_admin` | Boolean | - | 用户是否管理员 |
|
||||
| `data.is_login` | Boolean | - | 用户是否登录 |
|
||||
| `data.unread` | Array | `[]` | 用户未读的评论提醒数据 |
|
||||
| `data.unread_count` | Number | `0` | 用户未读的评论提醒数据总数 |
|
||||
|
||||
::: tip
|
||||
|
||||
- `data.unread` 数组中元素结构参考 [评论获取接口](#评论获取) `/api/get` **TIP**
|
||||
|
||||
:::
|
||||
|
||||
### 用户登录
|
||||
|
||||
**GET/POST** `/api/login`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ---------- | -------- | :--: | ---------------------------------- |
|
||||
| `name` | String | 是 | 待登录用户的昵称 |
|
||||
| `email` | String | 是 | 待登录用户的邮箱 |
|
||||
| `password` | String | 是 | 待登录用户的密码(管理员身份验证) |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ------------ | -------- | :----: | ---------------- |
|
||||
| `success` | Boolean | `true` | 用户登录成功 |
|
||||
| `data.token` | String | - | 登录的用户 Token |
|
||||
|
||||
### 提醒已读
|
||||
|
||||
**POST** `/api/mark-read`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------------ | -------- | :--: | -------------------- |
|
||||
| `notify_key` | String | 否 | 评论提醒唯一标识符 |
|
||||
| `name` | String | 否 | 评论提醒用户的昵称 |
|
||||
| `email` | String | 否 | 评论提醒用户的邮箱 |
|
||||
| `all_read` | Boolean | 否 | 评论提醒是否已读 |
|
||||
| `site_name` | String | 否 | 评论提醒所在站点名称 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------- | -------- | :----: | ------------ |
|
||||
| `success` | Boolean | `true` | 提醒已读成功 |
|
||||
|
||||
### 评论投票
|
||||
|
||||
**POST** `/api/vote`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ----------- | -------- | :--: | ----------------------------------------------------------------------------------------------------------- |
|
||||
| `target_id` | Number | 是 | 待投票评论 ID |
|
||||
| `type` | String | 否 | 待投票类型,前缀 `comment_`、`page_` 依次代表对评论投票、对页面投票,后缀 `_up`、`_down` 依次代表赞同、反对 |
|
||||
| `name` | String | 否 | 投票用户昵称 |
|
||||
| `email` | String | 否 | 投票用户邮箱 |
|
||||
| `site_name` | String | 否 | 投票目标评论或页面所在站点名称 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------------- | -------- | :----: | ------------------------------ |
|
||||
| `success` | Boolean | `true` | 评论投票成功 |
|
||||
| `data.vote_num` | Number | - | 目标评论或页面指定类型投票数据 |
|
||||
|
||||
### Artalk 版本
|
||||
|
||||
::: warning
|
||||
|
||||
此接口较特殊,返回结果不包含 `success`、`msg`、`data` 字段,直接返回包含指定字段的 JSON。
|
||||
|
||||
:::
|
||||
|
||||
**GET/POST** `/api/version`
|
||||
|
||||
**参数** 无
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ---------------- | -------- | :------: | ------------------------------- |
|
||||
| `app` | String | `artalk` | Artalk 后端程序名 |
|
||||
| `version` | String | - | Artalk 后端程序版本号 |
|
||||
| `commit_hash` | String | - | Artalk 后端程序 Git 提交哈希值 |
|
||||
| `fe_min_version` | String | - | Artalk 后端程序所需前端最低版本 |
|
||||
|
||||
## Captcha API
|
||||
|
||||
### 验证码刷新
|
||||
|
||||
**GET** `/api/captcha/refresh`
|
||||
|
||||
**参数** 无
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------------- | -------- | :----: | ------------------------------------ |
|
||||
| `success` | Boolean | `true` | 验证码刷新成功 |
|
||||
| `data.img_data` | String | - | 根据 IP 获取的验证码图片 Base64 编码 |
|
||||
|
||||
### 验证码检验
|
||||
|
||||
**GET** `/api/captcha/check`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------- | -------- | :--: | ------ |
|
||||
| `value` | String | 是 | 验证码 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------------- | -------- | :----: | -------------------------------------------------------- |
|
||||
| `success` | Boolean | `true` | 验证码检验成功 |
|
||||
| `data.img_data` | String | - | 新的验证码图片 Base64 编码,仅验证码检验出错时存在此字段 |
|
||||
|
||||
## Admin API
|
||||
|
||||
### 评论编辑
|
||||
|
||||
**POST** `/api/admin/comment-edit`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| -------------- | -------- | :--: | ------------------------------------------------- |
|
||||
| `id` | Number | 是 | 待编辑评论 ID,**不可修改** |
|
||||
| `site_name` | String | 否 | 待编辑评论所在站点名称,**不可修改** |
|
||||
| `content` | String | 否 | 待编辑评论正文 |
|
||||
| `page_key` | String | 否 | 待编辑评论所在页面唯一标识符 |
|
||||
| `nick` | String | 否 | 待编辑评论所属用户昵称 |
|
||||
| `email` | String | 否 | 待编辑评论所属用户邮箱 |
|
||||
| `link` | String | 否 | 待编辑评论所属用户链接 |
|
||||
| `rid` | String | 否 | 待编辑评论为回复评论时传入父评论 `ID`,否则为 `0` |
|
||||
| `ua` | String | 否 | 待编辑评论所属用户 User-Agent |
|
||||
| `ip` | String | 否 | 待编辑评论所属用户 IP |
|
||||
| `is_collapsed` | Boolean | 否 | 待编辑评论是否折叠 |
|
||||
| `is_pending` | Boolean | 否 | 待编辑评论是否待审 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| -------------- | -------- | :----: | ---------------- |
|
||||
| `success` | Boolean | `true` | 评论编辑成功 |
|
||||
| `data.comment` | Object | - | 编辑评论的新数据 |
|
||||
|
||||
::: tip
|
||||
|
||||
- `data.comment` 对象结构参考 [评论新增接口](#评论新增) `/api/add` 响应的 `data.comment`
|
||||
|
||||
:::
|
||||
|
||||
### 评论删除
|
||||
|
||||
::: danger
|
||||
|
||||
此接口不推荐外部调用。
|
||||
|
||||
调用此接口前请务必核实评论 ID,一旦调用成功将删除该评论下所有相关数据。
|
||||
|
||||
:::
|
||||
|
||||
**POST** `/api/admin/comment-del`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ----------- | -------- | :--: | ---------------------- |
|
||||
| `id` | Number | 是 | 待删除评论 ID |
|
||||
| `site_name` | String | 是 | 待删除评论所在站点名称 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------- | -------- | :----: | ------------ |
|
||||
| `success` | Boolean | `true` | 评论删除成功 |
|
||||
|
||||
### 页面获取
|
||||
|
||||
**POST** `/api/admin/page-get`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ----------- | -------- | :--: | ---------------------- |
|
||||
| `site_name` | String | 是 | 待获取页面目标站点名称 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ------------ | -------- | :----: | ------------------ |
|
||||
| `success` | Boolean | `true` | 页面获取成功 |
|
||||
| `data.pages` | Array | - | 目标站点的页面数据 |
|
||||
| `data.sites` | Array | - | 所有站点数据 |
|
||||
|
||||
::: tip
|
||||
|
||||
- `data.pages` 数组中元素结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
|
||||
- `data.sites` 数组中元素结构参考 [站点编辑接口](#站点编辑) `/api/admin/site-edit` 响应的 `data.site`
|
||||
|
||||
:::
|
||||
|
||||
### 页面编辑
|
||||
|
||||
**POST** `/api/admin/page-edit`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------------ | -------- | :--: | ------------------------------------ |
|
||||
| `id` | Number | 是 | 待编辑页面 ID,**不可修改** |
|
||||
| `site_name` | String | 否 | 待编辑页面所在站点名称,**不可修改** |
|
||||
| `key` | String | 否 | 待编辑页面唯一标识符 |
|
||||
| `title` | String | 否 | 待编辑页面标题 |
|
||||
| `admin_only` | Boolean | 否 | 待编辑页面是否仅管理员可评论 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ----------- | -------- | :----: | ---------------- |
|
||||
| `success` | Boolean | `true` | 页面编辑成功 |
|
||||
| `data.page` | Object | - | 编辑页面的新数据 |
|
||||
|
||||
::: tip
|
||||
|
||||
- `data.page` 对象结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
|
||||
|
||||
:::
|
||||
|
||||
### 页面删除
|
||||
|
||||
::: danger
|
||||
|
||||
此接口不推荐外部调用。
|
||||
|
||||
调用此接口前请务必核实页面 ID,一旦调用成功将删除该页面下所有相关数据。
|
||||
|
||||
:::
|
||||
|
||||
**POST** `/api/admin/page-del`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ----------- | -------- | :--: | ---------------------- |
|
||||
| `key` | String | 是 | 待删除页面唯一标识符 |
|
||||
| `site_name` | String | 是 | 待删除页面所在站点名称 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------- | -------- | :----: | ------------ |
|
||||
| `success` | Boolean | `true` | 页面删除成功 |
|
||||
|
||||
### 页面更新
|
||||
|
||||
**POST** `/api/admin/page-fetch`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------ | -------- | :--: | ------------- |
|
||||
| `id` | Number | 是 | 待更新页面 ID |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ----------- | -------- | :----: | ---------------- |
|
||||
| `success` | Boolean | `true` | 页面更新成功 |
|
||||
| `data.page` | Object | - | 更新页面的新数据 |
|
||||
|
||||
::: tip
|
||||
|
||||
- `data.page` 对象结构参考 [评论获取接口](#评论获取) `/api/get` 响应的 `data.page`
|
||||
|
||||
:::
|
||||
|
||||
### 站点获取
|
||||
|
||||
**POST** `/api/admin/site-get`
|
||||
|
||||
**参数** 无
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| ------------ | -------- | :----: | ------------ |
|
||||
| `success` | Boolean | `true` | 站点获取成功 |
|
||||
| `data.sites` | Array | - | 所有站点数据 |
|
||||
|
||||
::: tip
|
||||
|
||||
- `data.sites` 数组中元素结构参考 [站点编辑接口](#站点编辑) `/api/admin/site-edit` 响应的 `data.site`
|
||||
|
||||
:::
|
||||
|
||||
### 站点新增
|
||||
|
||||
**POST** `/api/admin/site-add`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------ | -------- | :--: | ------------------------------------------------- |
|
||||
| `name` | String | 是 | 待新增站点名称 |
|
||||
| `urls` | String | 是 | 待新增站点链接,如有多个需以英文半角符号 `,` 分割 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------------------- | -------- | :----: | ----------------------------------------------- |
|
||||
| `success` | Boolean | `true` | 站点新增成功 |
|
||||
| `data.site` | Object | - | 新增站点的数据 |
|
||||
| `data.site.id` | Number | - | 站点 ID |
|
||||
| `data.site.name` | String | - | 站点名称 |
|
||||
| `data.site.urls` | Array | - | 站点链接数组,元素为单个站点链接字符串 |
|
||||
| `data.site.urls_raw` | String | - | 站点链接数组合并字符串,以英文半角符号 `,` 分割 |
|
||||
| `data.site.first_url` | String | - | 站点第一链接 |
|
||||
|
||||
### 站点编辑
|
||||
|
||||
**POST** `/api/admin/site-edit`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------ | -------- | :--: | ---------------- |
|
||||
| `id` | Number | 是 | 待编辑站点 ID |
|
||||
| `name` | String | 是 | 待编辑站点新名称 |
|
||||
| `urls` | String | 是 | 待编辑站点新链接 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------------------- | -------- | :----: | ----------------------------------------------- |
|
||||
| `success` | Boolean | `true` | 站点编辑成功 |
|
||||
| `data.site` | Object | - | 编辑站点的新数据 |
|
||||
| `data.site.id` | Number | - | 站点 ID |
|
||||
| `data.site.name` | String | - | 站点名称 |
|
||||
| `data.site.urls` | Array | - | 站点链接数组,元素为单个站点链接字符串 |
|
||||
| `data.site.urls_raw` | String | - | 站点链接数组合并字符串,以英文半角符号 `,` 分割 |
|
||||
| `data.site.first_url` | String | - | 站点第一链接 |
|
||||
|
||||
### 站点删除
|
||||
|
||||
::: danger
|
||||
|
||||
此接口不推荐外部调用。
|
||||
|
||||
调用此接口前请务必核实站点 ID,一旦调用成功将删除该站点下所有相关数据。
|
||||
|
||||
:::
|
||||
|
||||
**POST** `/api/admin/site-del`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------------- | -------- | :--: | ------------------------------------------------------------------- |
|
||||
| `id` | Number | 是 | 待删除站点 ID |
|
||||
| `del_content` | Boolean | 否 | 是否删除站点所有数据,为 `false` 时仅删除站点配置而保留站点评论数据 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------- | -------- | :----: | ------------ |
|
||||
| `success` | Boolean | `true` | 站点删除成功 |
|
||||
|
||||
### 设置获取
|
||||
|
||||
**POST** `/api/admin/setting-get`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------ | -------- | :--: | -------------- |
|
||||
| `id` | Number | 是 | 管理员用户 ID |
|
||||
| `name` | String | 否 | 管理员用户昵称 |
|
||||
| `url` | String | 否 | 管理员用户链接 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------- | -------- | :----: | ------------ |
|
||||
| `success` | Boolean | `true` | 设置获取成功 |
|
||||
|
||||
### 设置保存
|
||||
|
||||
**POST** `/api/admin/setting-save`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| ------ | -------- | :--: | -------------- |
|
||||
| `id` | Number | 是 | 管理员用户 ID |
|
||||
| `name` | String | 否 | 管理员用户昵称 |
|
||||
| `url` | String | 否 | 管理员用户链接 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------- | -------- | :----: | ------------ |
|
||||
| `success` | Boolean | `true` | 设置保存成功 |
|
||||
|
||||
### 邮件发送
|
||||
|
||||
::: warning
|
||||
|
||||
页面收到评论、评论收到回复等满足需要发送邮件提醒条件时,后端将自动向目标地址发送邮件提醒,不需手动处理邮件发送。请勿滥用此接口。
|
||||
|
||||
:::
|
||||
|
||||
**POST** `/api/admin/send-mail`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| --------- | -------- | :--: | ---------- |
|
||||
| `subject` | String | 是 | 邮件主题 |
|
||||
| `body` | String | 是 | 邮件正文 |
|
||||
| `to_addr` | String | 是 | 邮件收件人 |
|
||||
|
||||
**响应**
|
||||
|
||||
| 字段名 | 数据类型 | 默认 | 说明 |
|
||||
| --------- | -------- | :----: | ------------ |
|
||||
| `success` | Boolean | `true` | 邮件发送成功 |
|
||||
|
||||
### Artrans 接口
|
||||
|
||||
::: warning
|
||||
|
||||
此接口暂不稳定,请避免使用!
|
||||
|
||||
:::
|
||||
|
||||
**POST** `/api/admin/artransfer`
|
||||
|
||||
**参数**
|
||||
|
||||
| 字段名 | 数据类型 | 必需 | 说明 |
|
||||
| --------- | -------- | :--: | ------------ |
|
||||
| `type` | String | 是 | 导入数据类型 |
|
||||
| `payload` | String | 否 | 导入数据 |
|
||||
|
||||
**响应** 无
|
||||
@@ -1,3 +0,0 @@
|
||||
# HTTP API
|
||||
|
||||
参考:<a href="/http-api.html" target="_blank">Artalk API 文档 (OpenAPI)</a>
|
||||
@@ -12,7 +12,7 @@
|
||||
git clone https://github.com/ArtalkJS/Artalk.git
|
||||
```
|
||||
|
||||
建议您先 fork 仓库,然后克隆 fork 后的仓库。
|
||||
建议你先 fork 仓库,然后克隆 fork 后的仓库。
|
||||
|
||||
导航到目录:
|
||||
|
||||
@@ -53,13 +53,13 @@ cd Artalk
|
||||
|
||||
4. **构建前端代码**:
|
||||
|
||||
- 当您对前端代码进行更改后,使用 `pnpm build:all` 构建完整的前端程序。
|
||||
- 当你对前端代码进行更改后,使用 `pnpm build:all` 构建完整的前端程序。
|
||||
- JavaScript 和 CSS 代码将在 `ui/artalk/dist` 目录中找到。
|
||||
- 前端代码由 GitHub Actions 自动部署到 NPM。
|
||||
|
||||
5. **构建后端代码**:
|
||||
|
||||
- 当您对后端代码进行更改后,注意后端程序会嵌入前端代码。
|
||||
- 当你对后端代码进行更改后,注意后端程序会嵌入前端代码。
|
||||
- 在构建后端之前,运行 `make build-frontend`(它运行 `scripts/build-frontend.sh`)。这将把嵌入的前端主程序和侧边栏前端程序放入 `/public` 目录。
|
||||
- 然后,使用 `make build` 构建后端程序。
|
||||
|
||||
@@ -69,7 +69,7 @@ cd Artalk
|
||||
请参考 [Artalk 插件开发指南](https://artalk.js.org/develop/plugin.html)。
|
||||
|
||||
- **Makefile**:
|
||||
您可以探索 `Makefile` 中的过程和命令。
|
||||
你可以探索 `Makefile` 中的过程和命令。
|
||||
|
||||
- **GitHub 上的自动化 CI**:
|
||||
GitHub 上的自动化 CI 流水线位于 `.github/workflows` 目录中,负责构建前端、后端和 Docker 镜像,发布 Docker 镜像到 Docker Hub,处理 npm 包发布,并创建 GitHub Releases,同时测试前端和后端。
|
||||
@@ -116,7 +116,7 @@ Artalk 是一个 monorepo 项目,这意味着所有源代码都在一个仓库
|
||||
|
||||
`make dev` 命令会带有调试符号构建后端,这方便使用 GDB 进行调试。
|
||||
|
||||
如果您使用 VSCode,可以使用 `F5` 键(或运行按钮)直接启动调试后端程序。
|
||||
如果你使用 VSCode,可以使用 `F5` 键(或运行按钮)直接启动调试后端程序。
|
||||
|
||||
### 构建后端
|
||||
|
||||
@@ -161,6 +161,52 @@ make build-frontend
|
||||
|
||||
更多详细信息,请参考 `scripts/build-frontend.sh` 脚本。
|
||||
|
||||
### 发布前端
|
||||
|
||||
核心的 Artalk 客户端代码通过 GitHub Actions 自动部署到 NPM。部署过程在 `.github/workflows/build-ui.yml` 文件中定义。
|
||||
|
||||
如果你在 monorepo 中编写 Artalk 插件,它不会被自动部署。你需要手动发布插件。要发布插件,请首先确保在 `package.json` 文件中更新版本号。然后,运行以下命令:
|
||||
|
||||
```sh
|
||||
pnpm publish --access public
|
||||
```
|
||||
|
||||
#### 检查已发布版本
|
||||
|
||||
`pnpm check:publish` 脚本旨在验证项目中的所有包是否在 npm 上发布了最新版本。它会自动跳过私有包,并允许使用 `-F` 选项进行筛选以检查特定包。
|
||||
|
||||
检查所有包:
|
||||
|
||||
```sh
|
||||
pnpm check:publish
|
||||
```
|
||||
|
||||
这将启动检查存储库中所有公共包的过程,以确保它们在 npm 上是最新的。
|
||||
|
||||
### 开发和调试 `@artalk/plugin-kit` 和 `eslint-plugin-artalk`
|
||||
|
||||
这个 monorepo 默认会从 NPM 安装最新版本的 `@artalk/plugin-kit` 和 `eslint-plugin-artalk` 发布包。要开发和调试这些包,请在仓库的根目录下运行以下命令:
|
||||
|
||||
```sh
|
||||
pnpm link --global --dir ui/eslint-plugin-artalk
|
||||
pnpm link --global --dir ui/plugin-kit
|
||||
|
||||
pnpm link eslint-plugin-artalk
|
||||
pnpm link @artalk/plugin-kit
|
||||
```
|
||||
|
||||
执行这些命令后,`eslint-plugin-artalk` 和 `@artalk/plugin-kit` 包将链接到本地开发环境中的 monorepo 工作空间。你可以在 `ui/eslint-plugin-artalk` 和 `ui/plugin-kit` 目录中修改源代码,这些更改会自动反映在 monorepo 工作空间中。如果你希望取消链接这些包,请运行以下命令:
|
||||
|
||||
```sh
|
||||
pnpm unlink eslint-plugin-artalk
|
||||
pnpm unlink @artalk/plugin-kit
|
||||
|
||||
pnpm uninstall --global eslint-plugin-artalk
|
||||
pnpm uninstall --global @artalk/plugin-kit
|
||||
```
|
||||
|
||||
更多详情请参考 [pnpm link 文档](https://pnpm.io/cli/link)。
|
||||
|
||||
## Docker 开发
|
||||
|
||||
### 构建 Docker 镜像
|
||||
@@ -175,7 +221,7 @@ docker build -t artalk:TAG .
|
||||
|
||||
### 跳过前端构建
|
||||
|
||||
如果您已经在 Docker 容器外部构建了前端,可以跳过容器内的前端构建过程以加快构建速度。使用以下命令:
|
||||
如果你已经在 Docker 容器外部构建了前端,可以跳过容器内的前端构建过程以加快构建速度。使用以下命令:
|
||||
|
||||
```sh
|
||||
docker build --build-arg SKIP_FRONTEND_BUILD=true -t artalk:latest .
|
||||
@@ -227,7 +273,7 @@ docker build --build-arg SKIP_FRONTEND_BUILD=true -t artalk:latest .
|
||||
|
||||
在 `internal/config/config.go` 文件中,有一个名为 `Config` 的结构体定义,该结构体用于将 yml 文件解析为 Go 结构体。该结构体包含更精确的类型定义。如果需要添加、修改或删除配置项,必须同时修改 `/conf` 目录中的配置文件模板和 `Config` 结构体。
|
||||
|
||||
当您修改配置文件后,请运行以下命令以更新配置数据缓存:
|
||||
当你修改配置文件后,请运行以下命令以更新配置数据缓存:
|
||||
|
||||
```sh
|
||||
make update-conf
|
||||
@@ -281,18 +327,18 @@ Swagger 定义位于后端代码的 `/server` 目录中。修改 Swagger 定义
|
||||
|
||||
## 翻译 (i18n)
|
||||
|
||||
如果您编写了新功能或进行了修复/重构,请使用以下命令通过解析源代码中的 `i18n.T` 函数调用来增量生成翻译文件:
|
||||
如果你编写了新功能或进行了修复/重构,请使用以下命令通过解析源代码中的 `i18n.T` 函数调用来增量生成翻译文件:
|
||||
|
||||
```sh
|
||||
make update-i18n
|
||||
```
|
||||
|
||||
如果您不是程序员,但希望帮助改进翻译,可以直接编辑 `/i18n` 目录中的翻译文件,然后提交 pull 请求。
|
||||
如果你不是程序员,但希望帮助改进翻译,可以直接编辑 `/i18n` 目录中的翻译文件,然后提交 pull 请求。
|
||||
|
||||
## 结尾
|
||||
|
||||
感谢您耐心阅读本指南,并感谢您对 Artalk 的兴趣和支持。我们深知,一个开源项目的成功依赖于每一位开发者的贡献。无论是通过代码、文档、测试还是反馈,您的参与是推动项目持续进步的动力。我们诚挚邀请您加入我们,共同改进和增强 Artalk。
|
||||
感谢你耐心阅读本指南,并感谢你对 Artalk 的兴趣和支持。我们深知,一个开源项目的成功依赖于每一位开发者的贡献。无论是通过代码、文档、测试还是反馈,你的参与是推动项目持续进步的动力。我们诚挚邀请你加入我们,共同改进和增强 Artalk。
|
||||
|
||||
通过合作,我们可以创建一个更加健壮和多功能的平台,造福整个社区。您的独特见解和专业知识是无价的,只有共同努力,我们才能实现显著的进步。无论您是经验丰富的开发者,还是刚刚起步的新手,我们的项目中总有您可以贡献的一席之地。
|
||||
通过合作,我们可以创建一个更加健壮和多功能的平台,造福整个社区。你的独特见解和专业知识是无价的,只有共同努力,我们才能实现显著的进步。无论你是经验丰富的开发者,还是刚刚起步的新手,我们的项目中总有你可以贡献的一席之地。
|
||||
|
||||
如果您有任何问题或需要帮助,请随时在我们的 GitHub 页面上的 issue 部分提问:<https://github.com/ArtalkJS/Artalk/issues>。再次感谢您的支持,我们期待与您合作。
|
||||
如果你有任何问题或需要帮助,请随时在我们的 GitHub 页面上的 issue 部分提问:<https://github.com/ArtalkJS/Artalk/issues>。再次感谢你的支持,我们期待与你合作。
|
||||
@@ -1,5 +1,9 @@
|
||||
# Frontend API
|
||||
|
||||
以下列出了一些主要的 Artalk 客户端 API,用于在前端代码中操作 Artalk 实例。
|
||||
|
||||
更多详细 API 信息可以通过 [TypeDoc 文档](https://artalk.js.org/typedoc/) 浏览。
|
||||
|
||||
## 安装依赖
|
||||
|
||||
用你喜欢的包管理器安装 Artalk:
|
||||
|
||||
@@ -17,7 +17,7 @@ pnpm add artalk
|
||||
import Artalk from 'artalk'
|
||||
import { onMounted, onBeforeUnmount, ref } from 'vue'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
const el = ref<HTMLElement>()
|
||||
|
||||
@@ -50,7 +50,7 @@ import Artalk from 'artalk'
|
||||
import { onMounted, onBeforeUnmount, ref, watch, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
const el = ref<HTMLElement>()
|
||||
const router = useRouter()
|
||||
@@ -98,32 +98,37 @@ onBeforeUnmount(() => {
|
||||
::: code-group
|
||||
|
||||
```tsx [React Hooks]
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { useCallback, useRef } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
import Artalk from 'artalk'
|
||||
|
||||
const ArtalkComment = () => {
|
||||
const container = useRef<HTMLDivElement>(null)
|
||||
const location = useLocation()
|
||||
const { pathname } = useLocation()
|
||||
const artalk = useRef<Artalk>()
|
||||
|
||||
useEffect(() => {
|
||||
artalk.current = Artalk.init({
|
||||
el: container.current!,
|
||||
pageKey: location.pathname,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk 的博客',
|
||||
// ...
|
||||
})
|
||||
const handleContainerInit = useCallback(
|
||||
(node: HTMLDivElement | null) => {
|
||||
if (!node) {
|
||||
return
|
||||
}
|
||||
if (artalk.current) {
|
||||
artalk.current.destroy()
|
||||
artalk.current = undefined
|
||||
}
|
||||
artalk.current = Artalk.init({
|
||||
el: node,
|
||||
pageKey: pathname,
|
||||
pageTitle: document.title,
|
||||
server: 'http://localhost:8080',
|
||||
site: 'Artalk 的博客',
|
||||
// ...
|
||||
})
|
||||
},
|
||||
[pathname],
|
||||
)
|
||||
|
||||
return () => {
|
||||
artalk.current?.destroy()
|
||||
}
|
||||
}, [container, location.pathname])
|
||||
|
||||
return <div ref={container}></div>
|
||||
return <div ref={handleContainerInit}></div>
|
||||
}
|
||||
|
||||
export default ArtalkComment
|
||||
@@ -133,7 +138,7 @@ export default ArtalkComment
|
||||
|
||||
```jsx [React Class]
|
||||
import React, { createRef } from 'react'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
import Artalk from 'artalk'
|
||||
|
||||
export default class Artalk extends React.Component {
|
||||
@@ -168,7 +173,7 @@ export default class Artalk extends React.Component {
|
||||
```tsx
|
||||
import { onCleanup, onMount } from 'solid-js'
|
||||
import Artalk from 'artalk'
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
const ArtalkComment = () => {
|
||||
let el: HTMLDivElement
|
||||
@@ -200,7 +205,7 @@ const ArtalkComment = () => {
|
||||
import Artalk from 'artalk'
|
||||
import { onMount, onDestroy } from 'svelte'
|
||||
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
|
||||
let el
|
||||
let artalk
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
|
||||
- [置入博客](./import-blog.md)
|
||||
- [置入框架](./import-framework.md)
|
||||
- [前端 API 文档](./fe-api.md)
|
||||
- [前端 Event](./event.md)
|
||||
- [前端 API](./fe-api.md)
|
||||
- [前端 Events](./event.md)
|
||||
- [前端 Types](https://artalk.js.org/typedoc/)
|
||||
- [前端配置](../guide/frontend/config.md)
|
||||
|
||||
**插件开发**
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# 插件开发
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/develop/plugin.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/develop/plugin.html';
|
||||
</script>
|
||||
@@ -1,7 +0,0 @@
|
||||
# 后端构建
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/develop/contributing.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/develop/contributing.html';
|
||||
</script>
|
||||
@@ -1,7 +0,0 @@
|
||||
# 数据
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/guide/transfer.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/guide/transfer.html';
|
||||
</script>
|
||||
@@ -1,7 +0,0 @@
|
||||
# 如何配置界面
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/guide/frontend/config.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/guide/frontend/config.html';
|
||||
</script>
|
||||
@@ -1,7 +0,0 @@
|
||||
# 后端部署
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/guide/deploy.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/guide/deploy.html';
|
||||
</script>
|
||||
@@ -49,11 +49,11 @@ docker exec -it artalk artalk admin
|
||||
<div id="Comments"></div>
|
||||
<script>
|
||||
Artalk.init({
|
||||
el: '#Comments', // 绑定元素的 Selector
|
||||
pageKey: '/post/1', // 固定链接
|
||||
pageTitle: '关于引入 Artalk 的这档子事', // 页面标题 (留空自动获取)
|
||||
el: '#Comments', // 绑定元素的 Selector
|
||||
pageKey: '/post/1', // 固定链接
|
||||
pageTitle: '关于引入 Artalk 的这档子事', // 页面标题 (留空自动获取)
|
||||
server: 'http://artalk.example.com:8080', // 后端地址
|
||||
site: 'Artalk 的博客', // 你的站点名
|
||||
site: 'Artalk 的博客', // 你的站点名
|
||||
})
|
||||
</script>
|
||||
```
|
||||
@@ -82,7 +82,7 @@ Artalk.init({
|
||||
- [反向代理 (Caddy, Nginx, Apache)](./backend/reverse-proxy.md)
|
||||
- [自编译 (通过最新代码构建)](../develop/contributing.md)
|
||||
|
||||
## Go 模块
|
||||
## Go 安装
|
||||
|
||||
如果你已经安装了 Golang 工具链,可以运行以下命令来编译和安装最新版本的 Artalk:
|
||||
|
||||
@@ -100,6 +100,14 @@ artalk server
|
||||
|
||||
## Linux 发行版
|
||||
|
||||
**Fedora (Copr)**:
|
||||
|
||||
```bash
|
||||
dnf install 'dnf-command(copr)'
|
||||
dnf copr enable @artalk/artalk
|
||||
dnf install artalk
|
||||
```
|
||||
|
||||
**Arch Linux (AUR)**:
|
||||
|
||||
```bash
|
||||
@@ -120,6 +128,8 @@ pkg install artalk
|
||||
|
||||
[](https://repology.org/project/artalk/versions)
|
||||
|
||||
[](https://copr.fedorainfracloud.org/coprs/g/artalk/artalk/)
|
||||
|
||||
## Docker Compose
|
||||
|
||||
创建一个工作目录,并编辑 `docker-compose.yml` 文件:
|
||||
@@ -164,22 +174,50 @@ docker-compose exec artalk bash # 进入容器
|
||||
|
||||
更多信息:[Docker](./backend/docker.md) / [环境变量](./env.md)
|
||||
|
||||
## 前端项目 (Node.js)
|
||||
## 客户端
|
||||
|
||||
如果你有前端或 Node.js Web 项目,以下指南将帮助你将 Artalk **客户端** 集成到你的 Web 项目中。
|
||||
|
||||
### 客户端安装
|
||||
|
||||
通过 NPM 安装 Artalk:
|
||||
|
||||
```bash
|
||||
::: code-group
|
||||
|
||||
```sh [npm]
|
||||
npm install artalk
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add artalk
|
||||
```
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm add artalk
|
||||
```
|
||||
|
||||
```sh [bun]
|
||||
bun add artalk
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
(你也可以选择通过 [CDN 资源](#客户端-cdn-资源) 引入).
|
||||
|
||||
### 客户端集成
|
||||
|
||||
在你的 Web 项目中引入 Artalk:
|
||||
|
||||
```js
|
||||
import 'artalk/dist/Artalk.css'
|
||||
import 'artalk/Artalk.css'
|
||||
import Artalk from 'artalk'
|
||||
|
||||
Artalk.init({
|
||||
// ...
|
||||
el: document.querySelector('#Comments'), // 挂载的 DOM 元素
|
||||
pageKey: '/post/1', // 固定链接
|
||||
pageTitle: '关于引入 Artalk 的这档子事', // 页面标题
|
||||
server: 'http://artalk.example.com:8080', // 后端地址
|
||||
site: 'Artalk 的博客', // 站点名
|
||||
})
|
||||
```
|
||||
|
||||
@@ -190,16 +228,63 @@ Artalk.init({
|
||||
- [前端 API](../develop/fe-api.md)
|
||||
- [前端配置](./frontend/config.md)
|
||||
|
||||
## 前端 CDN 资源
|
||||
### 客户端 CDN 资源
|
||||
|
||||
要通过 CDN 在浏览器中使用 Artalk,对于现代浏览器 (支持 [ES 模块](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)),可以使用 [esm.sh](https://esm.sh) 或 [esm.run](https://esm.run):
|
||||
|
||||
::: code-group
|
||||
|
||||
```html [ES 模块]
|
||||
<body>
|
||||
<div id="Comments"></div>
|
||||
|
||||
<script type="module">
|
||||
import Artalk from 'https://esm.sh/artalk@:ArtalkVersion:'
|
||||
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
```html [传统方式]
|
||||
<body>
|
||||
<div id="Comments"></div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.js"></script>
|
||||
<script>
|
||||
Artalk.init({
|
||||
el: '#Comments',
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
记得引入 CSS 文件:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.css">
|
||||
```
|
||||
|
||||
::: tip Artalk 最新版本
|
||||
|
||||
当前 Artalk 前端最新版本号为: **:ArtalkVersion:**
|
||||
Artalk 客户端的最新版本为:`:ArtalkVersion:`
|
||||
|
||||
若需升级前端将 URL 中的版本号数字部分替换即可。
|
||||
:::
|
||||
|
||||
Artalk 后端程序内嵌了前端 JS、CSS 文件,使用公共 CDN 资源请注意版本兼容性。
|
||||
注:Artalk 后端程序内嵌了前端 JS、CSS 文件,使用公共 CDN 资源请注意版本兼容性。
|
||||
|
||||
::: details 其他可选的 CDN 资源
|
||||
|
||||
**SUSTech Mirrors (境内)**
|
||||
|
||||
> <https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/artalk/:ArtalkVersion:/Artalk.js>
|
||||
>
|
||||
> <https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/artalk/:ArtalkVersion:/Artalk.css>
|
||||
|
||||
**CDNJS**
|
||||
|
||||
@@ -207,13 +292,6 @@ Artalk 后端程序内嵌了前端 JS、CSS 文件,使用公共 CDN 资源请
|
||||
>
|
||||
> <https://cdnjs.cloudflare.com/ajax/libs/artalk/:ArtalkVersion:/Artalk.css>
|
||||
|
||||
::: details 查看更多
|
||||
**SUSTech Mirrors (境内)**
|
||||
|
||||
> <https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/artalk/:ArtalkVersion:/Artalk.js>
|
||||
>
|
||||
> <https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/artalk/:ArtalkVersion:/Artalk.css>
|
||||
|
||||
**UNPKG**
|
||||
|
||||
> <https://unpkg.com/artalk@:ArtalkVersion:/dist/Artalk.js>
|
||||
|
||||
@@ -8,6 +8,10 @@ ArtalkLite 是 Artalk 的精简版本,相较于普通版,有以下区别:
|
||||
|
||||
ArtalkLite 随普通版一起发布,你可以将 CDN 地址文件名修改为 ArtalkLite 获取:
|
||||
|
||||
> https://unpkg.com/artalk@2/dist/ArtalkLite.js
|
||||
>
|
||||
> https://unpkg.com/artalk@2/dist/ArtalkLite.css
|
||||
```
|
||||
https://unpkg.com/artalk@:ArtalkVersion:/dist/ArtalkLite.js
|
||||
```
|
||||
|
||||
```
|
||||
https://unpkg.com/artalk@:ArtalkVersion:/dist/ArtalkLite.css
|
||||
```
|
||||
@@ -1,13 +1,15 @@
|
||||
# 界面配置
|
||||
|
||||
可在「[控制中心](./sidebar.md)」修改界面配置,而无需改动前端代码。另外也支持 [配置文件](../backend/config.md#界面配置-frontend) 和 [环境变量](../env.md#界面配置)。
|
||||
界面配置,也称为客户端配置、前端配置。可在「[控制中心](./sidebar.md#控制中心)」修改界面配置,而无需改动前端代码。另外也支持 [配置文件](../backend/config.md#界面配置-frontend) 和 [环境变量](../env.md#界面配置)。
|
||||
|
||||
界面配置的优先级如下:
|
||||
|
||||
```
|
||||
环境变量 > 配置文件 = 控制中心 > 前端代码
|
||||
前端代码 > 环境变量 > 控制中心 = 配置文件
|
||||
```
|
||||
|
||||
如果你通过环境变量、配置文件或是在控制中心修改了界面配置,遇到了配置未生效的情况,请考虑配置优先级的问题。
|
||||
|
||||
## 通过 `Artalk.init` 配置界面
|
||||
|
||||
在前端页面调用 `Artalk.init` 初始化时传入参数来配置界面,本文列出了所有可用的配置项。
|
||||
@@ -81,14 +83,20 @@ artalk.update({ ... })
|
||||
|
||||
Artalk 支持多站点统一管理,此项用于站点隔离。
|
||||
|
||||
### useBackendConf
|
||||
### preferRemoteConf
|
||||
|
||||
**引用后端的配置**
|
||||
**优先使用远程配置**
|
||||
|
||||
- 类型:`Boolean`
|
||||
- 默认值:`true`(默认启用)
|
||||
- 默认值:`false`(默认关闭)
|
||||
|
||||
可以在后端的配置文件中定义前端的配置,让前端配置始终引用后端。
|
||||
默认情况下,该配置项为关闭状态,Artalk 界面配置优先级为:优先使用本地的配置。本地配置是指在前端代码中通过 `Artalk.init` 传入的配置。
|
||||
|
||||
开启后,Artalk 会优先使用远程配置,如果远程配置不存在则使用本地配置。远程配置是指后端服务器程序返回的配置,用于动态配置 Artalk 客户端。你可以在「[控制中心](./sidebar.md#控制中心)」中修改用户界面的配置。
|
||||
|
||||
::: warning 更新注意
|
||||
从 v2.10.0 开始,`useBackendConf` 配置项已废弃并始终为 `true`,请使用 `preferRemoteConf` 替代。
|
||||
:::
|
||||
|
||||
## 国际化 (i18n)
|
||||
|
||||
@@ -278,6 +286,17 @@ Artalk 统计组件查询评论数和浏览量时,会通过该属性名来查
|
||||
|
||||
为了便于主题适配,可根据需要自定义属性名,例如将其替换为 `data-path`,则 HTML 标签为 `<span data-path="/t/1.html"></span>`。
|
||||
|
||||
### pageVote
|
||||
|
||||
**页面投票**
|
||||
|
||||
- 类型:`Boolean | { upBtnEl: string; downBtnEl: string; upCountEl: string; downCountEl: string; activeClass: string }`
|
||||
- 默认值: `true`
|
||||
|
||||
启用页面投票功能,用户可以为页面投票。
|
||||
|
||||
详情参考:[页面投票](./voting.md#页面投票)
|
||||
|
||||
### vote
|
||||
|
||||
**投票按钮**
|
||||
|
||||
@@ -30,7 +30,8 @@ locale: zh-CN
|
||||
| 前端界面 | [/ui/artalk/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/tree/master/ui/artalk/src/i18n) | [zh-CN.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk/src/i18n/zh-CN.ts) |
|
||||
| 后台界面 | [/ui/artalk-sidebar/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk-sidebar/src/i18n) | [zh-CN.ts](https://github.com/ArtalkJS/Artalk/blob/master/ui/artalk-sidebar/src/i18n/zh-CN.ts) |
|
||||
| 配置文件 | [/conf/artalk.example.[LANG].yml](https://github.com/ArtalkJS/Artalk/tree/master/conf) | [artalk.example.zh-CN.yml](https://github.com/ArtalkJS/Artalk/blob/master/conf/artalk.example.zh-CN.yml) |
|
||||
| 说明文档 | [/docs/[LANG]/\*\*/\*.md](https://github.com/ArtalkJS/Artalk/tree/master/docs) | [/docs/\*\*/\*.md](https://github.com/ArtalkJS/Artalk/tree/master/docs) |
|
||||
| 说明文档 | [/docs/docs/[LANG]/\*\*/\*.md](https://github.com/ArtalkJS/Artalk/tree/master/docs/docs) | [zh/\*\*/\*.md](https://github.com/ArtalkJS/Artalk/tree/master/docs/docs/zh) |
|
||||
| 官网首页 | [/docs/landing/src/i18n/[LANG].ts](https://github.com/ArtalkJS/Artalk/tree/master/docs/landing/src/i18n) | [zh-CN.ts](https://github.com/ArtalkJS/Artalk/blob/master/docs/landing/src/i18n/zh-CN.ts) |
|
||||
|
||||
更多参考:[开发文档](../../develop/index.md) / [CONTRIBUTING.md](https://github.com/ArtalkJS/Artalk/blob/master/CONTRIBUTING.md#translation)
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# 置入博客
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/develop/import-blog.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/develop/import-blog.html';
|
||||
</script>
|
||||
@@ -1,7 +0,0 @@
|
||||
# 置入框架
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/develop/import-framework.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/develop/import-framework.html';
|
||||
</script>
|
||||
@@ -1,7 +0,0 @@
|
||||
# 前端部署
|
||||
|
||||
本页面内容已移动至 <https://artalk.js.org/guide/deploy.html>。
|
||||
|
||||
<script setup lang="ts">
|
||||
if (!import.meta.env.SSR) window.location = 'https://artalk.js.org/guide/deploy.html';
|
||||
</script>
|
||||
@@ -0,0 +1,123 @@
|
||||
# 投票功能
|
||||
|
||||
Artalk 支持对评论和页面进行投票,用户可以点击“赞同”或“反对”按钮进行投票。评论列表支持通过投票数进行排序。评论投票功能可以帮助用户更好地了解评论的质量。
|
||||
|
||||
## 评论投票
|
||||
|
||||
评论投票功能默认启用,用户可以对评论进行投票。
|
||||
|
||||
你可以在控制台设置界面找到「界面配置」,修改「投票按钮」选项来启用或禁用评论投票功能。
|
||||
|
||||
投票按钮的环境变量:
|
||||
|
||||
```
|
||||
ATK_FRONTEND_VOTE=1
|
||||
```
|
||||
|
||||
投票按钮的配置文件:
|
||||
|
||||
```yaml
|
||||
frontend:
|
||||
vote: true
|
||||
```
|
||||
|
||||
### 反对按钮
|
||||
|
||||
默认情况下,Artalk 不会显示反对按钮。你可以在控制台设置界面找到「界面配置」,修改「反对按钮」选项来启用反对按钮。
|
||||
|
||||
反对按钮的环境变量:
|
||||
|
||||
```
|
||||
ATK_FRONTEND_VOTE_DOWN=1
|
||||
```
|
||||
|
||||
反对按钮的配置文件:
|
||||
|
||||
```yaml
|
||||
frontend:
|
||||
voteDown: true
|
||||
```
|
||||
|
||||
## 页面投票
|
||||
|
||||
Artalk 支持对页面进行投票,你需要在页面中添加元素来显示页面投票按钮,Artalk 在加载时会自动初始化页面投票按钮:
|
||||
|
||||
```html
|
||||
<div>
|
||||
<span class="artalk-page-vote-up"></span>
|
||||
<span class="artalk-page-vote-down"></span>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 已投票状态样式
|
||||
|
||||
当用户点击了页面投票按钮后,元素会被添加 `active` 类名,表示用户已经投票,例如:
|
||||
|
||||
```html
|
||||
<span class="artalk-page-vote-up active"></span>
|
||||
```
|
||||
|
||||
你可以通过 CSS 样式来自定义按钮的已投票样式:
|
||||
|
||||
```css
|
||||
.artalk-page-vote-up.active {
|
||||
color: #0083ff;
|
||||
}
|
||||
```
|
||||
|
||||
默认添加的类名为 `active`,可以在客户端通过 `pageVote.activeClass` 来修改:
|
||||
|
||||
```js
|
||||
Artalk.init({
|
||||
pageVote: {
|
||||
activeClass: 'active',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### 自定义元素选择器
|
||||
|
||||
Artalk 默认查找 `.artalk-page-vote-up` 和 `.artalk-page-vote-down` 作为投票按钮元素。
|
||||
|
||||
修改客户端的 `pageVote.upBtnEl` 和 `pageVote.downBtnEl` 配置可以自定义投票按钮选择器:
|
||||
|
||||
```js
|
||||
Artalk.init({
|
||||
pageVote: {
|
||||
upBtnEl: '.artalk-page-vote-up',
|
||||
downBtnEl: '.artalk-page-vote-down',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### 进一步自定义页面投票按钮
|
||||
|
||||
如果投票按钮内没有子元素,Artalk 会输出文字 "赞同 (n)" 到元素中。
|
||||
|
||||
如果你想输出投票数量到单独的元素,可以在按钮中添加一个标签,例如:
|
||||
|
||||
```html
|
||||
<div class="artalk-page-vote">
|
||||
<span class="artalk-page-vote-up">
|
||||
👍 (<span class="artalk-page-vote-up-count"></span>)
|
||||
</span>
|
||||
<span class="artalk-page-vote-down">
|
||||
👎 (<span class="artalk-page-vote-down-count"></span>)
|
||||
</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
更进一步,你可以将文字修改为图标,或者添加其他样式。
|
||||
|
||||
投票数选择器默认为 `.artalk-page-vote-up-count` 和 `.artalk-page-vote-down-count`,
|
||||
|
||||
可以修改 `pageVote.upCountEl` 和 `pageVote.downCountEl` 自定义投票数输出元素:
|
||||
|
||||
```js
|
||||
Artalk.init({
|
||||
pageVote: {
|
||||
upCountEl: '.artalk-page-vote-up-count',
|
||||
downCountEl: '.artalk-page-vote-down-count',
|
||||
},
|
||||
})
|
||||
```
|
||||
@@ -14,21 +14,20 @@
|
||||
"preview": "vite preview",
|
||||
"update:readme": "npx tsx ./scripts/update-readme.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"devDependencies": {
|
||||
"@headlessui/react": "^2.1.10",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@vitejs/plugin-react-swc": "^3.7.1",
|
||||
"i18next": "^23.16.0",
|
||||
"i18next-browser-languagedetector": "^8.0.0",
|
||||
"include-media": "^2.0.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-icons": "5.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@headlessui/react": "^2.1.8",
|
||||
"@types/react": "^18.3.7",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react-swc": "^3.7.0",
|
||||
"i18next": "^23.15.1",
|
||||
"i18next-browser-languagedetector": "^8.0.0",
|
||||
"react-i18next": "^15.0.2",
|
||||
"usehooks-ts": "^3.1.0"
|
||||
"react-i18next": "^15.0.3",
|
||||
"react-icons": "5.3.0",
|
||||
"usehooks-ts": "^3.1.0",
|
||||
"vanilla-lazyload": "^19.1.3"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 45 KiB |
@@ -9,10 +9,23 @@
|
||||
--color-bg: #fff;
|
||||
--color-bg-transparent: rgba(255, 255, 255, 0.9);
|
||||
--color-bg-grey: #f6f8fa;
|
||||
--color-bg-grey-deep: #f2f2f5;
|
||||
--color-bg-blue: #e5effe;
|
||||
--color-border: #e1e4ec;
|
||||
--color-border-light: #e4e4e4;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
background-color: var(--color-bg);
|
||||
}
|
||||
|
||||
body {
|
||||
padding-top: 70px;
|
||||
}
|
||||
|
||||
:host,
|
||||
html {
|
||||
font:
|
||||
16px 'SF Pro Display',
|
||||
'SF Pro Icons',
|
||||
@@ -20,8 +33,6 @@ body {
|
||||
'Helvetica',
|
||||
'Arial',
|
||||
sans-serif;
|
||||
overflow-x: hidden;
|
||||
background-color: var(--color-bg);
|
||||
color: var(--color-font);
|
||||
}
|
||||
|
||||
@@ -68,3 +79,7 @@ a {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.app-grey-bg {
|
||||
background: var(--color-bg-grey-deep);
|
||||
}
|
||||
@@ -8,11 +8,16 @@ import { useDarkMode } from './hooks/darkmode'
|
||||
import { Header } from './components/Header'
|
||||
import { Slogan } from './components/Slogan'
|
||||
import { Footer } from './components/Footer'
|
||||
import { SlightFeature } from './components/Features/SlightFeature'
|
||||
import { QuickFeature } from './components/Features/QuickFeature'
|
||||
import { FullFeature } from './components/Features/FullFeature'
|
||||
import { FuncFeature } from './components/Features/FuncFeature'
|
||||
import { SafeFeature } from './components/Features/SafeFeature'
|
||||
import { SlightFeature } from './components/Features/Slight'
|
||||
import { QuickFeature } from './components/Features/Quick'
|
||||
import { FullFeature } from './components/Features/Full'
|
||||
import { FuncsFeature } from './components/Features/Funcs'
|
||||
import { SafeFeature } from './components/Features/Safe'
|
||||
import { Plugins } from './components/Features/Plugins'
|
||||
import { Group } from './components/FeatureComps/Group'
|
||||
import { StartFeature } from './components/Features/Start'
|
||||
import { FrameworksFeature } from './components/Features/Frameworks'
|
||||
import { GreyCardsFeature } from './components/Features/GreyCards'
|
||||
|
||||
function App() {
|
||||
const { t, i18n } = useTranslation()
|
||||
@@ -33,11 +38,23 @@ function App() {
|
||||
<Header darkModeHandler={{ isDarkMode, toggle: toggleDarkMode }} />
|
||||
<Slogan />
|
||||
|
||||
<SlightFeature />
|
||||
<QuickFeature />
|
||||
<StartFeature />
|
||||
<GreyCardsFeature />
|
||||
|
||||
<FrameworksFeature />
|
||||
|
||||
<Group>
|
||||
<SlightFeature />
|
||||
<QuickFeature />
|
||||
</Group>
|
||||
<Group>
|
||||
<SafeFeature />
|
||||
</Group>
|
||||
<Group>
|
||||
<Plugins />
|
||||
</Group>
|
||||
<FullFeature />
|
||||
<FuncFeature />
|
||||
<SafeFeature />
|
||||
<FuncsFeature />
|
||||
|
||||
<Footer />
|
||||
</>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path d="M113.744 41.999a18.558 18.558 0 0 0-.8-.772c-.272-.246-.528-.524-.8-.771s-.528-.525-.8-.771c-.272-.247-.528-.525-.8-.772s-.528-.524-.8-.771-.528-.525-.8-.772-.528-.524-.8-.771c7.936 7.52 12.483 17.752 12.656 28.481 0 25.565-26.912 46.363-60 46.363-18.528 0-35.104-6.526-46.128-16.756l.8.772.8.771.8.772.8.771.8.772.8.771.8.771c11.008 10.662 27.952 17.527 46.928 17.527 33.088 0 60-20.797 60-46.285 0-10.893-4.864-21.215-13.456-29.33z"/><path fill="#fbf0df" d="M116.8 65.08c0 23.467-25.072 42.49-56 42.49s-56-19.023-56-42.49c0-14.55 9.6-27.401 24.352-35.023C43.904 22.435 53.088 14.628 60.8 14.628S75.104 21 92.448 30.058C107.2 37.677 116.8 50.53 116.8 65.08Z"/><path fill="#f6dece" d="M116.8 65.08a32.314 32.314 0 0 0-1.28-8.918c-4.368 51.377-69.36 53.846-94.912 38.48 11.486 8.584 25.66 13.144 40.192 12.928 30.88 0 56-19.054 56-42.49z"/><path fill="#fffefc" d="M39.248 27.234c7.152-4.135 16.656-11.896 26-11.911a15.372 15.372 0 0 0-4.448-.695c-3.872 0-8 1.93-13.2 4.83-1.808 1.018-3.68 2.144-5.664 3.317-3.728 2.222-8 4.736-12.8 7.251C13.904 37.972 4.8 51.071 4.8 65.08v1.836c9.696-33.033 27.312-35.547 34.448-39.682z"/><path fill="#ccbea7" d="M56.192 18.532A24.553 24.553 0 0 1 53.867 29.1a25.407 25.407 0 0 1-6.683 8.671c-.448.386-.096 1.127.48.91 5.392-2.02 12.672-8.068 9.6-20.272-.128-.695-1.072-.51-1.072.123zm3.632 0a24.474 24.474 0 0 1 3.646 10.12c.445 3.587.08 7.224-1.07 10.662-.192.54.496 1.003.88.556 3.504-4.32 6.56-12.899-2.592-22.156-.464-.4-1.184.216-.864.756zm4.416-.262a25.702 25.702 0 0 1 7.521 7.925A24.71 24.71 0 0 1 75.2 36.414c-.016.13.02.26.101.365a.543.543 0 0 0 .718.117.509.509 0 0 0 .221-.313c1.472-5.384.64-14.564-11.472-19.332-.64-.246-1.056.587-.528.957zM34.704 34.315a27.418 27.418 0 0 0 9.91-5.222 26.262 26.262 0 0 0 6.842-8.663c.288-.556 1.2-.34 1.056.277-2.768 12.343-12.032 14.92-17.792 14.58-.608.016-.592-.802-.016-.972z"/><path d="M60.8 111.443c-33.088 0-60-20.798-60-46.363 0-15.429 9.888-29.823 26.448-38.448 4.8-2.469 8.912-4.953 12.576-7.128 2.016-1.203 3.92-2.33 5.76-3.379C51.2 12.916 56 10.771 60.8 10.771c4.8 0 8.992 1.852 14.24 4.845 1.6.88 3.2 1.836 4.912 2.885 3.984 2.376 8.48 5.06 14.4 8.131 16.56 8.625 26.448 23.004 26.448 38.448 0 25.565-26.912 46.363-60 46.363zm0-96.814c-3.872 0-8 1.928-13.2 4.829-1.808 1.018-3.68 2.144-5.664 3.317-3.728 2.222-8 4.736-12.8 7.251C13.904 37.972 4.8 51.071 4.8 65.08c0 23.436 25.12 42.506 56 42.506s56-19.07 56-42.506c0-14.01-9.104-27.108-24.352-35.023-6.048-3.086-10.768-5.986-14.592-8.27-1.744-1.033-3.344-1.99-4.8-2.838-4.848-2.778-8.384-4.32-12.256-4.32z"/><path fill="#b71422" d="M72.08 76.343c-.719 2.839-2.355 5.383-4.672 7.267a11.07 11.07 0 0 1-6.4 2.9 11.13 11.13 0 0 1-6.608-2.9c-2.293-1.892-3.906-4.436-4.608-7.267a1.073 1.073 0 0 1 .05-.5 1.11 1.11 0 0 1 .272-.428 1.19 1.19 0 0 1 .958-.322h19.744a1.185 1.185 0 0 1 .947.33 1.073 1.073 0 0 1 .317.92z"/><path fill="#ff6164" d="M54.4 83.733a11.24 11.24 0 0 0 6.592 2.932 11.239 11.239 0 0 0 6.576-2.932 16.652 16.652 0 0 0 1.6-1.65 10.904 10.904 0 0 0-3.538-2.564 11.26 11.26 0 0 0-4.302-1 10.121 10.121 0 0 0-4.549 1.192 9.71 9.71 0 0 0-3.451 3.097c.368.323.688.632 1.072.925z"/><path d="M54.656 82.514a8.518 8.518 0 0 1 2.97-2.347 8.836 8.836 0 0 1 3.734-.862 9.78 9.78 0 0 1 6.4 2.608c.368-.386.72-.787 1.056-1.188-2.035-1.87-4.726-2.933-7.536-2.978a10.487 10.487 0 0 0-4.335.975 10.125 10.125 0 0 0-3.489 2.666c.378.396.779.772 1.2 1.126z"/><path d="M60.944 87.436a12.078 12.078 0 0 1-7.12-3.086c-2.477-2.02-4.22-4.75-4.976-7.791-.054-.27-.045-.55.027-.817a1.83 1.83 0 0 1 .389-.726 2.25 2.25 0 0 1 .81-.595 2.32 2.32 0 0 1 .998-.192h19.744c.343-.007.683.06.996.196a2.3 2.3 0 0 1 .812.591c.182.212.313.46.382.728.07.267.076.545.018.815-.756 3.042-2.5 5.771-4.976 7.791a12.078 12.078 0 0 1-7.104 3.086zm-9.872-11.417c-.256 0-.32.108-.336.139.676 2.638 2.206 4.999 4.368 6.742a10.122 10.122 0 0 0 5.84 2.7 10.207 10.207 0 0 0 5.84-2.67c2.155-1.745 3.679-4.106 4.352-6.741a.333.333 0 0 0-.14-.113.348.348 0 0 0-.18-.026z"/><path fill="#febbd0" d="M85.152 77.3c5.17 0 9.36-2.377 9.36-5.308s-4.19-5.307-9.36-5.307c-5.17 0-9.36 2.376-9.36 5.307 0 2.931 4.19 5.307 9.36 5.307zm-48.432 0c5.17 0 9.36-2.377 9.36-5.308s-4.19-5.307-9.36-5.307c-5.17 0-9.36 2.376-9.36 5.307 0 2.931 4.19 5.307 9.36 5.307z"/><path d="M41.12 69.863a9.052 9.052 0 0 0 4.902-1.425 8.578 8.578 0 0 0 3.254-3.812 8.22 8.22 0 0 0 .508-4.913 8.41 8.41 0 0 0-2.408-4.357 8.92 8.92 0 0 0-4.514-2.33 9.12 9.12 0 0 0-5.096.48 8.755 8.755 0 0 0-3.96 3.131 8.287 8.287 0 0 0-1.486 4.725c0 2.252.927 4.412 2.577 6.005 1.65 1.594 3.888 2.492 6.223 2.496zm39.632 0a9.054 9.054 0 0 0 4.915-1.403 8.582 8.582 0 0 0 3.275-3.802 8.22 8.22 0 0 0 .528-4.917 8.408 8.408 0 0 0-2.398-4.368 8.92 8.92 0 0 0-4.512-2.344 9.12 9.12 0 0 0-5.103.473 8.756 8.756 0 0 0-3.967 3.13 8.287 8.287 0 0 0-1.49 4.73c-.004 2.245.914 4.4 2.555 5.994 1.64 1.593 3.869 2.495 6.197 2.507z"/><path fill="#fff" d="M38.4 61.902a3.4 3.4 0 0 0 1.844-Line truncated
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg height="512" viewBox="0 0 5120 5120" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m2560 0a2560 2560 0 1 1 0 5120 2560 2560 0 0 1 0-5120z"/><path d="m2460 1449c-744 0-1324 469-1324 1052 0 550 533 901 1359 884l25-1 91-3-23 60 3 6a668 668 0 0 1 18 47l2 6 3 10 4 14 3 9 4 10 3 11 4 16 5 17 3 11 5 18 5 19 4 19 5 20 4 14 5 22 5 22 7 30 3 16 5 24 5 25 6 26 7 37 6 30 8 42 4 21 7 33 6 34 8 46 9 48 8 50 9 51 9 52 9 54 9 56 7 43 11 73 5 30 12 77 9 63 8 48 9 66 5 33c549-73 1037-339 1393-728l11-12-51-190-135-505-84-314-74-276-46-168-29-106-17-64-16-56-6-24-4-13-2-7-2-6c-78-251-229-473-435-634-242-189-549-288-907-288zm-654 2669c-65-18-133 20-152 85l-1 3-112 416a2287 2287 0 0 0 215 93l17 7 121-451 1-3c16-66-23-133-89-150zm697-305c-66-18-134 20-153 85l-1 3-170 630v3a125 125 0 0 0 241 65l1-3 170-630v-3l3-14 1-5-4-21-6-29-4-18a125 125 0 0 0 -78-63zm-1185-649-8 19-1 4-170 630-1 3a125 125 0 0 0 241 66l1-3 154-572c-80-42-153-92-216-147zm-405-725c-66-17-134 21-153 85l-1 3-170 630v3a125 125 0 0 0 241 66l1-3 170-630v-3c16-66-23-133-88-151zm3811-143c-65-17-133 21-152 85l-1 3-170 630-1 3a125 125 0 0 0 242 66v-3l171-630v-4c16-65-23-132-89-150zm-4182-841a2284 2284 0 0 0 -267 838 124 124 0 0 0 62 38c65 17 133-21 152-85l1-3 170-630 1-3c16-66-23-133-89-151a127 127 0 0 0 -30-4zm3752 4c-66-17-133 21-153 85v3l-170 630-1 3a125 125 0 0 0 241 66l1-3 170-630 1-3c16-66-24-133-89-151z" fill="#fff"/><path d="m2620 1870a160 160 0 1 1 0 320 160 160 0 0 1 0-320z"/><path d="m1282 860c-65-17-133 21-152 85l-1 3-170 630-1 3a125 125 0 0 0 241 66l1-3 170-630 1-4c16-65-23-132-89-150zm2185 119c-66-17-134 21-153 85l-1 3-114 424a1399 1399 0 0 1 211 128l11 9 134-495v-3c16-66-23-133-88-151zm-1112-710a2299 2299 0 0 0 -238 34l-17 3-158 587-1 3a125 125 0 0 0 241 65l1-3 170-630 1-3a124 124 0 0 0 1-56zm1564 435-33 124-1 3a125 125 0 0 0 241 65l1-3 4-13a2312 2312 0 0 0 -197-165zm-989-414-60 223-1 3a125 125 0 0 0 241 65l1-3 63-235a2286 2286 0 0 0 -226-50z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1 @@
|
||||
<svg height="800" viewBox="0 0 24 24" width="800" xmlns="http://www.w3.org/2000/svg"><g fill="none"><path d="m21.4679537 3.20617761c.7135135 1.47335907-1.4548263 1.63088803-1.3436294 2.28880308.203861 1.18610039.0648649 2.94671815-.0926641 4.67953671-.2687258 2.9374517 1.9274132 9.9706563-2.650193 12.7969112-.8617761.5374517-2.9096525.8339768-4.9297297.8803089h-.0092665-.0092664c-2.0200772-.0463321-4.34594591-.3428572-5.20772197-.8803089-4.56833977-2.8262549-2.37220078-9.8594595-2.63166024-12.7969112-.16679536-1.73281856-.3057915-3.49343632-.09266409-4.67953671.11119691-.65791505-2.05714286-.8061776-1.34362934-2.28880308.61158301-1.26949807 2.12200772-.14826255 2.5019305-.54671815 1.93667954-2.01081081 4.29034749-2.54826255 6.14362934-2.5945946h1.019305c1.8440155.0926641 4.1976834.5930502 6.1436294 2.5945946.3799227.3984556 1.881081-.72277992 2.5019305.54671815zm-10.0355213 7.70038609c-.0833977.0370656-.2223938.9451738.203861.9915058.2872587.0277992 1.0749035.1204633 1.2602317 0 .36139-.2316602.3243243-.7876448.1204633-.9266409-.3428571-.2223939-1.4918919-.1111969-1.584556-.0648649zm-2.35366792-6.80154439c-.95444016-.11119692-2.55752896.77837837-2.7984556 2.66872586-.25945946 1.96447877 2.05714286 3.91042473 4.28108112 1.96447877 1.1953668-1.04710425 1.6123552-4.27181467-1.48262552-4.63320463zm6.44942082 0c-3.0949807.36138996-2.6779922 3.58610038-1.4826255 4.63320463 2.2239383 1.94594596 4.5405406 0 4.2810811-1.96447877-.2316602-1.89034749-1.834749-2.77992278-2.7984556-2.66872586z" fill="#8cc5e7"/><path d="m12.3127413 8.98841699c.5837838-.08339768 1.9830116.58378378 1.8903475 1.37142861-.1111969.9173745-3.6046332 1.0378378-3.7899614-.0555985-.1111969-.66718146.4169884-1.09343629 1.8996139-1.31583011zm7.8857143 7.38532821c-.2872587-.0092664-.4725869-.3891892-.4725869-.6208494 0-.4169885.0555985-.9081082.36139-1.1212356.6301158-.4355212 1.1305019 1.7513514.1111969 1.742085zm-15.78069498 0c-1.01930502.0092664-.51891892-2.1776062.11119691-1.742085.3057915.2131274.36138996.7042471.36138996 1.1212356 0 .2316602-.18532818.611583-.47258687.6208494zm13.84401548 6.7181467c.1853281.2687259.1945946.454054-.1019305.5930502-1.130502.5189189-2.1405406-.1760618-1.7606178-.3706564.8061776-.407722 1.3065637-1.0471042 1.8625483-.2223938zm-11.90733595.0926641c.55598456-.8247104 1.05637066-.1853282 1.86254827.2223938.37992278.1945946-.63011583.8895753-1.76061776.3706564-.2965251-.1389962-.28725869-.3243243-.10193051-.5930502z" fill="#b8937f"/><path d="m19.7351351 3.42857143c.0463321-.1945946.5281854-.28725869.7969112.04633204.3243244.3984556-.4725868.94517375-.5096525.72277993-.0926641-.6023166-.3428571-.57451738-.2872587-.76911197zm-14.85405402 0c.05559846.19459459-.19459459.16679537-.28725869.76911197-.03706563.22239382-.83397683-.32432433-.50965251-.72277993.25945946-.33359073.74131275-.24092664.7969112-.04633204zm10.86023162 4.51274131c-.5834174 0-1.0563706-.47295325-1.0563706-1.05637066 0-.5834174.4729532-1.05637065 1.0563706-1.05637065s1.0563707.47295325 1.0563707 1.05637065c0 .58341741-.4729533 1.05637066-1.0563707 1.05637066zm-.2779922-1.17683398c.184237 0 .3335907-.14935365.3335907-.33359073 0-.18423707-.1493537-.33359073-.3335907-.33359073-.1842371 0-.3335908.14935366-.3335908.33359073 0 .18423708.1493537.33359073.3335908.33359073zm-4.1050193 2.66872587c.1111969-.42625482.5003861-.56525096.815444-.57451737.8061776-.01853282 1.1119691.41698842 1.1397683.75984556.0555985.58378378-2.2054054.72277988-1.9552123-.18532819zm-2.48339773-1.49189189c-.5834174 0-1.05637065-.47295325-1.05637065-1.05637066 0-.5834174.47295325-1.05637065 1.05637065-1.05637065.58341741 0 1.05637066.47295325 1.05637066 1.05637065 0 .58341741-.47295325 1.05637066-1.05637066 1.05637066zm.27799228-1.17683398c.18423708 0 .33359074-.14935365.33359074-.33359073 0-.18423707-.14935366-.33359073-.33359074-.33359073-.18423707 0-.33359073.14935366-.33359073.33359073 0 .18423708.14935366.33359073.33359073.33359073z" fill="#000"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1 @@
|
||||
<svg height="800" viewBox="0 0 512 512" width="800" xmlns="http://www.w3.org/2000/svg"><path d="m256.4 25.8-200 115.5-.4 230.2 199.6 114.7 200-115.5.4-230.2zm92.6 328.8-18.4 10.7-18.6-11v-79.3h-112v79.6l-18.4 10.7-18.6-11v-197l18.5-10.6 18.5 10.8v79.5h112v-79.6l18.5-10.6 18.5 10.8z" fill="#0e83cd"/></svg>
|
||||
|
After Width: | Height: | Size: 306 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 370 391" xmlns="http://www.w3.org/2000/svg"><g clip-rule="evenodd" fill-rule="evenodd"><path d="m207.5 22.4 114.4 66.6c13.5 7.9 21.9 22.4 21.9 38v136.4c0 17.3-9.3 33.3-24.5 41.8l-113.5 63.9c-15.1 8.5-33.5 8.4-48.5-.2l-104.5-60.1c-16.4-9.5-26.6-27-26.6-45.9v-129.5c0-19.1 9.9-36.8 26.1-46.8l102.8-63.5c16-9.9 36.2-10.1 52.4-.7z" fill="#ff4088" stroke="#c9177e" stroke-width="27"/><path d="m105.6 298.2v-207.2h43.4v75.5h71.9v-75.5h43.5v207.2h-43.5v-90.6h-71.9v90.6z" fill="#fff"/></g></svg>
|
||||
|
After Width: | Height: | Size: 506 B |
@@ -0,0 +1 @@
|
||||
<svg height="292" viewBox="0 0 256 292" width="256" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" x1="68.188441%" x2="27.822694%" y1="17.486831%" y2="89.755142%"><stop offset="0" stop-color="#41873f"/><stop offset=".3288" stop-color="#418b3d"/><stop offset=".6352" stop-color="#419637"/><stop offset=".9319" stop-color="#3fa92d"/><stop offset="1" stop-color="#3fae2a"/></linearGradient><linearGradient id="b" x1="43.276547%" x2="159.245277%" y1="55.168777%" y2="-18.306138%"><stop offset=".1376" stop-color="#41873f"/><stop offset=".4032" stop-color="#54a044"/><stop offset=".7136" stop-color="#66b848"/><stop offset=".9081" stop-color="#6cc04a"/></linearGradient><linearGradient id="c" x1="-4.388804%" x2="101.499239%" y1="49.997207%" y2="49.997207%"><stop offset=".09191646" stop-color="#6cc04a"/><stop offset=".2864" stop-color="#66b848"/><stop offset=".5968" stop-color="#54a044"/><stop offset=".8624" stop-color="#41873f"/></linearGradient><mask id="d" fill="#fff"><path d="m134.922587 1.83244962c-4.343584-2.44326616-9.50159-2.44326616-13.845175 0l-114.29056154 65.96818658c-4.34358429 2.4432662-6.78685046 7.0583244-6.78685046 11.9448568v132.207847c0 4.886533 2.71474019 9.501591 6.78685046 11.944857l114.29056154 65.968188c4.343585 2.443264 9.501591 2.443264 13.845175 0l114.290561-65.968188c4.343585-2.443266 6.786852-7.058324 6.786852-11.944857v-132.207847c0-4.8865324-2.71474-9.5015906-6.786852-11.9448568z" fill="#fff"/></mask><mask id="e" fill="#fff"><path d="m134.922587 1.83244962c-4.343584-2.44326616-9.50159-2.44326616-13.845175 0l-114.29056154 65.96818658c-4.34358429 2.4432662-6.78685046 7.0583244-6.78685046 11.9448568v132.207847c0 4.886533 2.71474019 9.501591 6.78685046 11.944857l114.29056154 65.968188c4.343585 2.443264 9.501591 2.443264 13.845175 0l114.290561-65.968188c4.343585-2.443266 6.786852-7.058324 6.786852-11.944857v-132.207847c0-4.8865324-2.71474-9.5015906-6.786852-11.9448568z" fill="#fff"/></mask><path d="m134.922587 1.83244962c-4.343584-2.44326616-9.50159-2.44326616-13.845175 0l-114.29056154 65.96818658c-4.34358429 2.4432662-6.78685046 7.0583244-6.78685046 11.9448568v132.207847c0 4.886533 2.71474019 9.501591 6.78685046 11.944857l114.29056154 65.968188c4.343585 2.443264 9.501591 2.443264 13.845175 0l114.290561-65.968188c4.343585-2.443266 6.786852-7.058324 6.786852-11.944857v-132.207847c0-4.8865324-2.71474-9.5015906-6.786852-11.9448568z" fill="url(#a)"/><path d="m249.484623 67.8006362-114.83351-65.96818658c-1.085896-.54294803-2.443266-1.08589606-3.529162-1.35737008l-128.67868483 220.43690346c1.08589607 1.35737 2.44326618 2.443266 3.80063626 3.257688l114.83350957 65.968186c3.257689 1.90032 7.058325 2.443267 10.587487 1.35737l120.805939-220.9798506c-.814422-1.0858961-1.90032-1.9003183-2.986215-2.7147402z" fill="url(#b)" mask="url(#d)"/><path d="m249.756098 223.898195c3.257687-1.900317 5.700955-5.158004 6.786849-8.687166l-125.963944-215.00742421c-3.257688-.54294817-6.78685-.2714742-9.773065 1.62884406l-114.01908754 65.69671245 122.97773054 224.2375407c1.628844-.271475 3.529162-.814423 5.158006-1.628845z" fill="url(#c)" mask="url(#e)"/></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="none" viewBox="-11 -10.13 22 20.27" xmlns="http://www.w3.org/2000/svg"><circle fill="#087ea4" r="2"/><g stroke="#087ea4"><ellipse rx="10" ry="4.5"/><ellipse rx="10" ry="4.5" transform="matrix(.5 .8660254 -.8660254 .5 0 0)"/><ellipse rx="10" ry="4.5" transform="matrix(-.5 .8660254 -.8660254 -.5 0 0)"/></g></svg>
|
||||
|
After Width: | Height: | Size: 323 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="18.918325" x2="119.14456" y1="3.92209" y2="52.626405"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="73.901874" x2="56.35222" y1="27.750978" y2="86.196156"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="11.592552" x2="112.945829" y1="53.189926" y2="122.100494"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="57.318256" x2="16.422732" y1="61.481735" y2="211.458824"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient><path d="m128 29.683s-42.667-31.396-75.673-24.151l-2.415.805c-4.83 1.61-8.855 4.025-11.27 7.245l-1.61 2.415-12.076 20.931 20.93 4.025c8.856 5.636 20.127 8.05 30.592 5.636l37.031 7.245z" fill="#76b3e1"/><path d="m128 29.683s-42.667-31.396-75.673-24.151l-2.415.805c-4.83 1.61-8.855 4.025-11.27 7.245l-1.61 2.415-12.076 20.931 20.93 4.025c8.856 5.636 20.127 8.05 30.592 5.636l37.031 7.245z" fill="url(#a)" opacity=".3"/><path d="m38.642 29.683-3.22.805c-13.687 4.025-17.712 16.906-10.467 28.176 8.05 10.465 24.956 16.1 38.641 12.076l49.912-16.906s-42.665-31.396-74.866-24.151z" fill="#518ac8"/><path d="m38.642 29.683-3.22.805c-13.687 4.025-17.712 16.906-10.467 28.176 8.05 10.465 24.956 16.1 38.641 12.076l49.912-16.906s-42.665-31.396-74.866-24.151z" fill="url(#b)" opacity=".3"/><path d="m104.654 65.91a36.226 36.226 0 0 0 -38.641-12.076l-49.913 16.1-16.1 28.177 90.164 15.295 16.1-28.981c3.22-5.635 2.415-12.075-1.61-18.516z" fill="url(#c)"/><path d="m88.553 94.085a36.226 36.226 0 0 0 -38.641-12.075l-49.912 16.1s42.667 32.202 75.673 24.152l2.415-.806c13.686-4.025 18.516-16.905 10.465-27.37z" fill="url(#d)"/></svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1 @@
|
||||
<svg enable-background="new 0 0 98.1 118" viewBox="0 0 98.1 118" xmlns="http://www.w3.org/2000/svg"><path d="m91.8 15.6c-10.9-15.7-32.6-20.3-48.2-10.4l-27.5 17.6c-7.5 4.7-12.7 12.4-14.2 21.1-1.3 7.3-.2 14.8 3.3 21.3-2.4 3.6-4 7.6-4.7 11.8-1.6 8.9.5 18.1 5.7 25.4 11 15.7 32.6 20.3 48.2 10.4l27.5-17.5c7.5-4.7 12.7-12.4 14.2-21.1 1.3-7.3.2-14.8-3.3-21.3 2.4-3.6 4-7.6 4.7-11.8 1.7-9-.4-18.2-5.7-25.5" fill="#ff3e00"/><path d="m40.9 103.9c-8.9 2.3-18.2-1.2-23.4-8.7-3.2-4.4-4.4-9.9-3.5-15.3.2-.9.4-1.7.6-2.6l.5-1.6 1.4 1c3.3 2.4 6.9 4.2 10.8 5.4l1 .3-.1 1c-.1 1.4.3 2.9 1.1 4.1 1.6 2.3 4.4 3.4 7.1 2.7.6-.2 1.2-.4 1.7-.7l27.4-17.5c1.4-.9 2.3-2.2 2.6-3.8s-.1-3.3-1-4.6c-1.6-2.3-4.4-3.3-7.1-2.6-.6.2-1.2.4-1.7.7l-10.5 6.7c-1.7 1.1-3.6 1.9-5.6 2.4-8.9 2.3-18.2-1.2-23.4-8.7-3.1-4.4-4.4-9.9-3.4-15.3.9-5.2 4.1-9.9 8.6-12.7l27.5-17.5c1.7-1.1 3.6-1.9 5.6-2.5 8.9-2.3 18.2 1.2 23.4 8.7 3.2 4.4 4.4 9.9 3.5 15.3-.2.9-.4 1.7-.7 2.6l-.5 1.6-1.4-1c-3.3-2.4-6.9-4.2-10.8-5.4l-1-.3.1-1c.1-1.4-.3-2.9-1.1-4.1-1.6-2.3-4.4-3.3-7.1-2.6-.6.2-1.2.4-1.7.7l-27.4 17.5c-1.4.9-2.3 2.2-2.6 3.8s.1 3.3 1 4.6c1.6 2.3 4.4 3.3 7.1 2.6.6-.2 1.2-.4 1.7-.7l10.5-6.7c1.7-1.1 3.6-1.9 5.6-2.5 8.9-2.3 18.2 1.2 23.4 8.7 3.2 4.4 4.4 9.9 3.5 15.3-.9 5.2-4.1 9.9-8.6 12.7l-27.5 17.5c-1.7 1.1-3.6 1.9-5.6 2.5" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="none" height="65" viewBox="0 0 66 65" width="66" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="m33.5 59c-19.6338 0-26.5-6.8676-26.5-26.5 0-19.6331 6.8662-26.5 26.5-26.5s26.5 6.8669 26.5 26.5c0 19.6324-6.8662 26.5-26.5 26.5zm-14.2692-34.6538h28.5384v-4.077h-28.5384zm0 10.1923h20.3846v-4.077h-20.3846zm0 10.1923h24.4615v-4.077h-24.4615z" fill="#000" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 405 B |
@@ -0,0 +1 @@
|
||||
<svg fill="none" height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="6.48163" x2="39.05" y1="1.9759" y2="48.2064"><stop offset="0" stop-color="#49c7ff"/><stop offset="1" stop-color="#bd36ff"/></linearGradient><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="4.39484" x2="38.3093" y1="5.32467" y2="31.584"><stop offset="0" stop-color="#41d1ff"/><stop offset="1" stop-color="#bd34fe"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="21.8138" x2="26.2464" y1="13.7047" y2="28.807"><stop offset="0" stop-color="#ffea83"/><stop offset=".0833333" stop-color="#ffdd35"/><stop offset="1" stop-color="#ffa800"/></linearGradient><clipPath id="d"><path d="m0 0h48v48h-48z"/></clipPath><g clip-path="url(#d)"><path d="m5.03628 7.87818c-.28292-2.03863 1.11964-3.92352 3.13271-4.21003l25.51481-3.6314097c2.0131-.2865103 3.8743 1.1338597 4.1572 3.1724897l5.1227 36.91257c.2829 2.0386-1.1196 3.9235-3.1327 4.2101l-25.5148 3.6314c-2.0131.2865-3.8743-1.1339-4.1572-3.1725z" fill="url(#a)"/><path d="m6.85877 7.6188c-.14146-1.01932.55982-1.96177 1.56635-2.10502l25.51478-3.63141c1.0066-.14326 1.9372.56693 2.0787 1.58624l5.1226 36.91259c.1415 1.0193-.5598 1.9618-1.5663 2.105l-25.5148 3.6314c-1.0066.1433-1.9372-.5669-2.0787-1.5862z" fill="#fff"/><path d="m33.1857 14.9195-7.3352 19.2381c-.1514.3971-.6742.4724-.9328.1343l-12.5834-16.458c-.2817-.3684-.0126-.9.4463-.8815l10.1247.4083c.0645.0026.1291-.0066.1903-.027l9.4132-3.1345c.4343-.1446.8415.2886.6769.7203z" fill="url(#b)"/><path d="m27.0251 12.5756-7.0899 2.4671c-.1165.0405-.1908.1559-.1806.2804l.637 7.7399c.015.1823.1988.2998.3672.2347l1.9638-.7585c.1838-.071.3795.0746.3679.2736l-.1803 3.0775c-.012.2071.1991.3533.3848.2664l1.1998-.5614c.186-.0869.3972.0596.3847.2671l-.294 4.8355c-.0184.3025.3904.4088.5158.1342l.0837-.1834 4.2448-12.8473c.071-.2151-.133-.4205-.3451-.3474l-2.0328.7007c-.191.0658-.3844-.0961-.3565-.2986l.6869-4.9822c.028-.2027-.166-.3648-.3572-.2983z" fill="url(#c)"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 261.76 226.69" xmlns="http://www.w3.org/2000/svg"><g transform="matrix(1.3333 0 0 -1.3333 161.096398 .001167)"><path d="m0 0-22.669-39.264-22.669 39.264h-75.491l98.16-170.02 98.16 170.02z" fill="#41b883"/><path d="m0 0-22.669-39.264-22.669 39.264h-36.227l58.896-102.01 58.896 102.01z" fill="#34495e"/></g></svg>
|
||||
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 150 KiB |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 122.52 122.523" xmlns="http://www.w3.org/2000/svg"><g fill="#21759b"><path d="m8.708 61.26c0 20.802 12.089 38.779 29.619 47.298l-25.069-68.686c-2.916 6.536-4.55 13.769-4.55 21.388z"/><path d="m96.74 58.608c0-6.495-2.333-10.993-4.334-14.494-2.664-4.329-5.161-7.995-5.161-12.324 0-4.831 3.664-9.328 8.825-9.328.233 0 .454.029.681.042-9.35-8.566-21.807-13.796-35.489-13.796-18.36 0-34.513 9.42-43.91 23.688 1.233.037 2.395.063 3.382.063 5.497 0 14.006-.667 14.006-.667 2.833-.167 3.167 3.994.337 4.329 0 0-2.847.335-6.015.501l19.138 56.925 11.501-34.493-8.188-22.434c-2.83-.166-5.511-.501-5.511-.501-2.832-.166-2.5-4.496.332-4.329 0 0 8.679.667 13.843.667 5.496 0 14.006-.667 14.006-.667 2.835-.167 3.168 3.994.337 4.329 0 0-2.853.335-6.015.501l18.992 56.494 5.242-17.517c2.272-7.269 4.001-12.49 4.001-16.989z"/><path d="m62.184 65.857-15.768 45.819c4.708 1.384 9.687 2.141 14.846 2.141 6.12 0 11.989-1.058 17.452-2.979-.141-.225-.269-.464-.374-.724z"/><path d="m107.376 36.046c.226 1.674.354 3.471.354 5.404 0 5.333-.996 11.328-3.996 18.824l-16.053 46.413c15.624-9.111 26.133-26.038 26.133-45.426.001-9.137-2.333-17.729-6.438-25.215z"/><path d="m61.262 0c-33.779 0-61.262 27.481-61.262 61.26 0 33.783 27.483 61.263 61.262 61.263 33.778 0 61.265-27.48 61.265-61.263-.001-33.779-27.487-61.26-61.265-61.26zm0 119.715c-32.23 0-58.453-26.223-58.453-58.455 0-32.23 26.222-58.451 58.453-58.451 32.229 0 58.45 26.221 58.45 58.451 0 32.232-26.221 58.455-58.45 58.455z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1,7 +1,7 @@
|
||||
.feature {
|
||||
min-height: 90vh;
|
||||
|
||||
.content {
|
||||
& > .content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
@@ -1,27 +1,27 @@
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import './FeatureBase.scss'
|
||||
import './Base.scss'
|
||||
import { useIsElementVisible } from '../../hooks/visible'
|
||||
|
||||
interface FeatureBaseProps extends React.ComponentProps<'div'> {
|
||||
onVisibleChange?: (visible: boolean) => void
|
||||
}
|
||||
|
||||
export const FeatureBase: React.FC<FeatureBaseProps> = (props) => {
|
||||
export const Base: React.FC<FeatureBaseProps> = (props) => {
|
||||
const { className, onVisibleChange, ...otherProps } = props
|
||||
|
||||
const refElem = useRef<HTMLDivElement>(null)
|
||||
const isSlightFeatureVisible = useIsElementVisible(refElem)
|
||||
const isVisible = useIsElementVisible(refElem)
|
||||
|
||||
const classNames = [
|
||||
'feature',
|
||||
'container',
|
||||
isSlightFeatureVisible ? 'visible' : '',
|
||||
isVisible ? 'visible' : '',
|
||||
...(className?.split(' ') || []),
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
onVisibleChange && onVisibleChange(isSlightFeatureVisible)
|
||||
}, [onVisibleChange, isSlightFeatureVisible])
|
||||
onVisibleChange && onVisibleChange(isVisible)
|
||||
}, [onVisibleChange, isVisible])
|
||||
|
||||
return (
|
||||
<div ref={refElem} className={classNames.join(' ')} {...otherProps}>
|
||||
@@ -0,0 +1,33 @@
|
||||
.feature-block {
|
||||
min-height: 520px;
|
||||
padding: 64px 76px;
|
||||
border-radius: 32px;
|
||||
background-color: #e8f0fe;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
& > .content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
main {
|
||||
}
|
||||
|
||||
aside {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.feature-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.feature-desc {
|
||||
margin: 20px 0;
|
||||
font-size: 22px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import './BlockBase.scss'
|
||||
import { useIsElementVisible } from '../../hooks/visible'
|
||||
|
||||
interface FeatureBaseProps extends React.ComponentProps<'div'> {
|
||||
onVisibleChange?: (visible: boolean) => void
|
||||
}
|
||||
|
||||
export const BlockBase: React.FC<FeatureBaseProps> = (props) => {
|
||||
const { className, onVisibleChange, ...otherProps } = props
|
||||
|
||||
const refElem = useRef<HTMLDivElement>(null)
|
||||
const isVisible = useIsElementVisible(refElem)
|
||||
|
||||
const classNames = ['feature-block', isVisible ? 'visible' : '', ...(className?.split(' ') || [])]
|
||||
|
||||
useEffect(() => {
|
||||
onVisibleChange && onVisibleChange(isVisible)
|
||||
}, [onVisibleChange, isVisible])
|
||||
|
||||
return (
|
||||
<div ref={refElem} className={classNames.join(' ')} {...otherProps}>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
.feature-desc {
|
||||
font-size: 24px;
|
||||
font-size: 1.7rem;
|
||||
line-height: 2;
|
||||
color: var(--color-font-secondary);
|
||||
margin: 60px 0;
|
||||
@@ -1,6 +1,6 @@
|
||||
import './FeatureDesc.scss'
|
||||
import './Desc.scss'
|
||||
|
||||
export const FeatureDesc: React.FC<{
|
||||
export const Desc: React.FC<{
|
||||
children: React.ReactNode
|
||||
}> = ({ children }) => {
|
||||
return <div className="feature-desc">{children}</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
.feature-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
column-gap: 64px;
|
||||
row-gap: 40px;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 64px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import './Group.scss'
|
||||
|
||||
export const Group: React.FC<{
|
||||
children: React.ReactNode
|
||||
}> = ({ children }) => {
|
||||
return <div className="feature-group container">{children}</div>
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
.feature-title {
|
||||
font-size: 40px;
|
||||
font-size: 3rem;
|
||||
font-weight: bold;
|
||||
|
||||
.bold {
|
||||
font-size: 1.7em;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import './Title.scss'
|
||||
import { Reveal } from '../Reveal'
|
||||
|
||||
interface TitleProps {
|
||||
text: string
|
||||
color: string
|
||||
}
|
||||
|
||||
export const Title: React.FC<TitleProps> = (props) => {
|
||||
return (
|
||||
<Reveal>
|
||||
<div className="feature-title" style={{ color: props.color }}>
|
||||
{props.text.slice(0, 1)}
|
||||
{props.text.slice(1, props.text.length)}
|
||||
</div>
|
||||
</Reveal>
|
||||
)
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import './FeatureTitle.scss'
|
||||
import { Reveal } from './Reveal'
|
||||
|
||||
interface FeatureTitleProps {
|
||||
text: string
|
||||
color: string
|
||||
}
|
||||
|
||||
export const FeatureTitle: React.FC<FeatureTitleProps> = (props) => {
|
||||
return (
|
||||
<Reveal>
|
||||
<div className="feature-title" style={{ color: props.color }}>
|
||||
<span className="bold">{props.text.slice(0, 1)}</span>
|
||||
{props.text.slice(1, props.text.length)}
|
||||
</div>
|
||||
</Reveal>
|
||||
)
|
||||
}
|
||||