Skip to content

Commit

Permalink
refactor(ui): improve modularity, lifecycle, and types (#1007)
Browse files Browse the repository at this point in the history
- Introduce a service dependency container for better management (#1006).
  - Replace original `services` definitions with `provide` and `inject` methods.
  - Recommend calling `inject` at the beginning of `ArtalkPlugin` to explicitly inject required dependencies.
- Replace `load` with `mount` for improved lifecycle handling.
  - Track local config.
  - Fix potential language setting not working issue. (Fixes #973)
- Refine Type definitions for clarity and maintainability.
  - See [TypeDoc](https://artalk.js.org/typedoc/) for updates.
- Enhance config logic with `ConfigManager`.
  - Deprecate `ctx.conf` and `ctx.$root`; use `getConf()` and `getEl()` instead.
  - Update client default config settings. (Fixes #1001)
- Improve event handling with `EventManager` refactor.
- Update plugin and editor architecture for greater flexibility.
  - Further eliminate global variables and avoid directly passing the `Context` interface as a function parameter. Instead, use more explicit and specific types and parameters.
- Remove deprecated and redundant code for a cleaner structure.

BREAKING CHANGE: This update changes the UI client's export Types. Although we aim to maintain backward compatibility, it may still affect downstream UI programs. Please refer to the [TypeDoc](https://artalk.js.org/typedoc/).
  • Loading branch information
qwqcode authored Oct 18, 2024
1 parent 437892c commit 20be96f
Show file tree
Hide file tree
Showing 102 changed files with 1,512 additions and 1,021 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"build:auth": "pnpm -F @artalk/plugin-auth build",
"build:plugin-kit": "pnpm -F @artalk/plugin-kit build",
"build:eslint-plugin": "pnpm -F eslint-plugin-artalk build",
"build:docs": "pnpm build && pnpm -F=docs-landing build && pnpm -F=docs-swagger swagger:build && pnpm -F=docs build:docs && pnpm patch:docs",
"build:typedoc": "pnpm typedoc",
"build:docs": "pnpm build && pnpm -F=docs-landing build && pnpm -F=docs-swagger swagger:build && pnpm -F=docs build:docs && pnpm patch:docs && pnpm build:typedoc",
"patch:docs": "cp -rf docs/landing/dist/* docs/swagger/dist/* docs/docs/.vitepress/dist",
"lint:eslint": "eslint .",
"lint:prettier": "prettier --check .",
Expand Down Expand Up @@ -52,6 +53,7 @@
"sass": "1.78.0",
"terser": "5.33.0",
"tsx": "^4.19.1",
"typedoc": "^0.26.10",
"typescript": "5.6.2",
"typescript-eslint": "^8.6.0",
"vite": "5.4.6",
Expand Down
55 changes: 55 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"out": "docs/docs/.vitepress/dist/typedoc",
"entryPoints": ["ui/artalk/src/main.ts"],
"tsconfig": "ui/artalk/tsconfig.json",
"logLevel": "Error"
}
82 changes: 52 additions & 30 deletions ui/artalk/src/artalk.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,65 @@
import './style/main.scss'

import type { EventHandler } from './lib/event-manager'
import Context from './context'
import { handelCustomConf, convertApiOptions } from './config'
import Services from './service'
import { handelCustomConf, convertApiOptions, getRootEl } from './config'
import * as Stat from './plugins/stat'
import { Api } from './api'
import type { TInjectedServices } from './service'
import { GlobalPlugins, PluginOptions, load } from './load'
import type { ArtalkConfigPartial, EventPayloadMap, ArtalkPlugin, ContextApi } from '@/types'
import { GlobalPlugins, PluginOptions, mount } from './mount'
import { ConfigService } from './services/config'
import { EventsService } from './services/events'
import type {
ConfigPartial,
EventPayloadMap,
ArtalkPlugin,
Context as IContext,
EventHandler,
} from '@/types'

/**
* Artalk
*
* @see https://artalk.js.org
*/
export default class Artalk {
public ctx!: ContextApi
public ctx: IContext

constructor(conf: ArtalkConfigPartial) {
// Init Config
const handledConf = handelCustomConf(conf, true)
constructor(conf: ConfigPartial) {
// Init Root Element
const $root = getRootEl(conf)
$root.classList.add('artalk')
$root.innerHTML = ''
conf.darkMode == true && $root.classList.add('atk-dark-mode')

// Init Context
this.ctx = new Context(handledConf)
const ctx = (this.ctx = new Context($root))

// Init Services
Object.entries(Services).forEach(([name, initService]) => {
const obj = initService(this.ctx)
obj && this.ctx.inject(name as keyof TInjectedServices, obj) // auto inject deps to ctx
})
// Init required services
;(() => {
// Init event manager
EventsService(ctx)

// Init config service
ConfigService(ctx)
})()

// Apply local conf first
ctx.updateConf(conf)

// Trigger created event
ctx.trigger('created')

// Load plugins and remote config, then mount Artalk
const mountArtalk = async () => {
await mount(conf, ctx)

// Trigger mounted event
ctx.trigger('mounted')
}

if (import.meta.env.DEV && import.meta.env.VITEST) {
global.devLoadArtalk = () => load(this.ctx)
global.devMountArtalk = mountArtalk
} else {
load(this.ctx)
mountArtalk()
}
}

Expand All @@ -45,13 +70,12 @@ export default class Artalk {

/** Get the root element of Artalk */
public getEl() {
return this.ctx.$root
return this.ctx.getEl()
}

/** Update config of Artalk */
public update(conf: ArtalkConfigPartial) {
public update(conf: ConfigPartial) {
this.ctx.updateConf(conf)
return this
}

/** Reload comment list of Artalk */
Expand All @@ -61,10 +85,7 @@ export default class Artalk {

/** Destroy instance of Artalk */
public destroy() {
this.ctx.trigger('unmounted')
while (this.ctx.$root.firstChild) {
this.ctx.$root.removeChild(this.ctx.$root.firstChild)
}
this.ctx.destroy()
}

/** Add an event listener */
Expand Down Expand Up @@ -92,7 +113,7 @@ export default class Artalk {
// ===========================

/** Init Artalk */
public static init(conf: ArtalkConfigPartial): Artalk {
public static init(conf: ConfigPartial): Artalk {
return new Artalk(conf)
}

Expand All @@ -103,7 +124,7 @@ export default class Artalk {
}

/** Load count widget */
public static loadCountWidget(c: ArtalkConfigPartial) {
public static loadCountWidget(c: ConfigPartial) {
const conf = handelCustomConf(c, true)

Stat.initCountWidget({
Expand All @@ -119,14 +140,15 @@ export default class Artalk {
// ===========================
// Deprecated
// ===========================

/** @deprecated Please use `getEl()` instead */
public get $root() {
return this.ctx.$root
console.warn('`$root` is deprecated, please use `getEl()` instead')
return this.getEl()
}

/** @description Please use `getConf()` instead */
public get conf() {
return this.ctx.getConf()
console.warn('`conf` is deprecated, please use `getConf()` instead')
return this.getConf()
}
}
16 changes: 8 additions & 8 deletions ui/artalk/src/comment/comment-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import UADetect from '../lib/detect'
import CommentUI from './render'
import CommentActions from './actions'
import $t from '@/i18n'
import type { CommentData, ArtalkConfig, ContextApi } from '@/types'
import type { CommentData, Config, Context } from '@/types'

export interface CommentOptions {
// Hooks
Expand All @@ -22,16 +22,16 @@ export interface CommentOptions {
voteDown: boolean
uaBadge: boolean
nestMax: number
gravatar: ArtalkConfig['gravatar']
heightLimit: ArtalkConfig['heightLimit']
avatarURLBuilder: ArtalkConfig['avatarURLBuilder']
scrollRelativeTo: ArtalkConfig['scrollRelativeTo']
dateFormatter: ArtalkConfig['dateFormatter']
gravatar: Config['gravatar']
heightLimit: Config['heightLimit']
avatarURLBuilder: Config['avatarURLBuilder']
scrollRelativeTo: Config['scrollRelativeTo']
dateFormatter: Config['dateFormatter']

// TODO: Move to plugin folder and remove from core
getApi: () => Api
replyComment: ContextApi['replyComment']
editComment: ContextApi['editComment']
replyComment: Context['replyComment']
editComment: Context['editComment']
}

export default class CommentNode {
Expand Down
Loading

0 comments on commit 20be96f

Please sign in to comment.