diff --git a/ui/plugin-auth/DialogExample.tsx b/ui/plugin-auth/DialogExample.tsx index 14bd3b2b..88e8fb21 100644 --- a/ui/plugin-auth/DialogExample.tsx +++ b/ui/plugin-auth/DialogExample.tsx @@ -1,9 +1,9 @@ -import type { ContextApi } from 'artalk' import { createSignal } from 'solid-js' import { Dialog } from './Dialog' +import type { AuthContext } from './types' interface DialogExampleProps { - ctx: ContextApi + ctx: AuthContext onClose: () => void } diff --git a/ui/plugin-auth/DialogMain.tsx b/ui/plugin-auth/DialogMain.tsx index 6c59da1d..65c4dd21 100644 --- a/ui/plugin-auth/DialogMain.tsx +++ b/ui/plugin-auth/DialogMain.tsx @@ -1,5 +1,4 @@ -import type { ContextApi } from 'artalk' -import { Show, createResource, createSignal, onMount } from 'solid-js' +import { createResource, createSignal } from 'solid-js' import { Dialog } from './Dialog' import { DialogMethods } from './DialogMethods' import { DialogPageLogin } from './DialogPageLogin' @@ -7,9 +6,10 @@ import { DialogPageRegister } from './DialogPageRegister' import { createLayer } from './lib/layer' import { DialogMerge } from './merge/DialogMerge' import { fetchMethods, LoginMethod } from './lib/methods' +import type { AuthContext } from './types' interface DialogMainProps { - ctx: ContextApi + ctx: AuthContext onClose: () => void onSkip: () => void } @@ -18,7 +18,7 @@ export const DialogMain = (props: DialogMainProps) => { const { ctx, onClose, onSkip, ...others } = props const [methods] = createResource(async () => { - return fetchMethods(ctx) + return fetchMethods(ctx.getApi()) .then((m) => m.map((mm) => { if (mm.name === 'email') mm.onClick = () => setPage('login') @@ -43,7 +43,7 @@ export const DialogMain = (props: DialogMainProps) => { const onComplete = () => { onClose() - ctx.get('editor').getUI().$header.style.display = 'none' + ctx.getEditor().getUI().$header.style.display = 'none' // Check need to merge ctx diff --git a/ui/plugin-auth/DialogMethods.tsx b/ui/plugin-auth/DialogMethods.tsx index 969158a4..5b8c6578 100644 --- a/ui/plugin-auth/DialogMethods.tsx +++ b/ui/plugin-auth/DialogMethods.tsx @@ -1,11 +1,11 @@ import { createEffect, createMemo, createSignal, For, Resource } from 'solid-js' -import type { ContextApi } from 'artalk' import { startOAuthLogin } from './lib/oauth-login' import { loginByToken } from './lib/token-login' import { LoginMethod } from './lib/methods' +import type { AuthContext } from './types' export interface DialogMethodsProps { - ctx: ContextApi + ctx: AuthContext methods: Resource changeTitle: (title: string) => void onComplete: () => void @@ -23,7 +23,7 @@ export const DialogMethods = (props: DialogMethodsProps) => { (async () => { const url = /^(http|https):\/\//.test(m.link!) ? m.link! - : `${ctx.getConf().server}${m.link}` + : `${ctx.getConf().get().server}${m.link}` const { token } = await startOAuthLogin(ctx, url) loginByToken(ctx, token) props.onComplete() diff --git a/ui/plugin-auth/DialogPageLogin.tsx b/ui/plugin-auth/DialogPageLogin.tsx index f0f84897..d240ec07 100644 --- a/ui/plugin-auth/DialogPageLogin.tsx +++ b/ui/plugin-auth/DialogPageLogin.tsx @@ -1,9 +1,9 @@ -import type { ContextApi } from 'artalk' import { createStore } from 'solid-js/store' import { loginByApiRes } from './lib/token-login' +import type { AuthContext } from './types' export interface DialogPageLoginProps { - ctx: ContextApi + ctx: AuthContext onRegisterNowClick: () => void changeTitle: (title: string) => void onComplete: () => void diff --git a/ui/plugin-auth/DialogPageRegister.tsx b/ui/plugin-auth/DialogPageRegister.tsx index 1d9ef360..4b4f8285 100644 --- a/ui/plugin-auth/DialogPageRegister.tsx +++ b/ui/plugin-auth/DialogPageRegister.tsx @@ -1,11 +1,11 @@ -import type { ContextApi } from 'artalk' import { Show, createSignal, createEffect } from 'solid-js' import { createStore, reconcile } from 'solid-js/store' import { VerifyButton } from './VerifyButton' import { loginByApiRes } from './lib/token-login' +import type { AuthContext } from './types' export interface DialogPageRegisterProps { - ctx: ContextApi + ctx: AuthContext onLoginNowClick: () => void changeTitle: (title: string) => void onComplete: () => void diff --git a/ui/plugin-auth/EditorUser.tsx b/ui/plugin-auth/EditorUser.tsx index 786783ec..85d40560 100644 --- a/ui/plugin-auth/EditorUser.tsx +++ b/ui/plugin-auth/EditorUser.tsx @@ -1,13 +1,13 @@ -import type { ContextApi } from 'artalk' import { Show, onCleanup, createSignal } from 'solid-js' import { render } from 'solid-js/web' +import { AuthContext } from './types' import { createLayer } from './lib/layer' import { UserProfileDialog } from './UserProfileDialog' -const EditorUser = ({ ctx }: { ctx: ContextApi }) => { +const EditorUser = ({ ctx }: { ctx: AuthContext }) => { const logoutHandler = () => { window.confirm(ctx.$t('logoutConfirm')) && - ctx.get('user').update({ + ctx.getUser().update({ token: '', name: '', email: '', @@ -16,17 +16,17 @@ const EditorUser = ({ ctx }: { ctx: ContextApi }) => { }) } - const getUser = () => ({ ...ctx.get('user').getData() }) // Must clone the object to avoid reactivity problem + const getUser = () => ({ ...ctx.getUser().getData() }) // Must clone the object to avoid reactivity problem const [user, setUser] = createSignal(getUser()) const userChangedHandler = (u: any) => { setUser(getUser()) } - ctx.on('user-changed', userChangedHandler) + ctx.getEvents().on('user-changed', userChangedHandler) onCleanup(() => { - ctx.off('user-changed', userChangedHandler) + ctx.getEvents().off('user-changed', userChangedHandler) }) const openUserProfileDialog = () => { @@ -62,8 +62,8 @@ const EditorUser = ({ ctx }: { ctx: ContextApi }) => { ) } -export const RenderEditorUser = (ctx: ContextApi) => { - const editor = ctx.get('editor') +export const RenderEditorUser = (ctx: AuthContext) => { + const editor = ctx.getEditor() const findEl = () => editor.getEl().querySelector('.atk-editor-user-wrap') if (!findEl()) { diff --git a/ui/plugin-auth/UserProfileDialog.tsx b/ui/plugin-auth/UserProfileDialog.tsx index 9cee2801..e945c4d9 100644 --- a/ui/plugin-auth/UserProfileDialog.tsx +++ b/ui/plugin-auth/UserProfileDialog.tsx @@ -1,11 +1,12 @@ -import { ContextApi, LocalUser } from 'artalk' +import { LocalUser } from 'artalk' import { createResource, createSignal, Resource, Show } from 'solid-js' import { createStore } from 'solid-js/store' +import type { AuthContext } from './types' import { Dialog } from './Dialog' import { VerifyButton } from './VerifyButton' export interface UserProfileDialogProps { - ctx: ContextApi + ctx: AuthContext onClose: () => void } @@ -17,7 +18,7 @@ export const UserProfileDialog = (props: UserProfileDialogProps) => { const [userInfo] = createResource(async () => { const { data } = await ctx.getApi().user.getUser() if (!data.is_login) { - ctx.get('user').logout() + ctx.getUser().logout() onClose() throw new Error('No login') } @@ -43,7 +44,7 @@ export const UserProfileDialog = (props: UserProfileDialogProps) => { } const UserBasicProfileForm = ( - ctx: ContextApi, + ctx: AuthContext, onChangePassword: () => void, setTitle: (t: string) => void, user: Resource, @@ -69,7 +70,7 @@ const UserBasicProfileForm = ( ...fields, }) .then(({ data: { user } }) => { - ctx.get('user').update(user) + ctx.getUser().update(user) onClose() }) .catch((e) => { @@ -136,7 +137,7 @@ const UserBasicProfileForm = ( } const UserChangePasswordForm = ( - ctx: ContextApi, + ctx: AuthContext, setTitle: (t: string) => void, user: Resource, onClose: () => void, @@ -166,7 +167,7 @@ const UserChangePasswordForm = ( code: fields.code, }) .then((res) => { - ctx.get('user').logout() + ctx.getUser().logout() onClose() }) .catch((err) => { diff --git a/ui/plugin-auth/VerifyButton.tsx b/ui/plugin-auth/VerifyButton.tsx index c704ba71..01a1a525 100644 --- a/ui/plugin-auth/VerifyButton.tsx +++ b/ui/plugin-auth/VerifyButton.tsx @@ -1,8 +1,8 @@ -import type { ContextApi } from 'artalk' import { createSignal } from 'solid-js' +import type { AuthContext } from './types' interface VerifyButtonProps { - ctx: ContextApi + ctx: AuthContext getEmail: () => string onSend?: () => void } diff --git a/ui/plugin-auth/lib/layer.ts b/ui/plugin-auth/lib/layer.ts index 53fffad0..66d1b62e 100644 --- a/ui/plugin-auth/lib/layer.ts +++ b/ui/plugin-auth/lib/layer.ts @@ -1,9 +1,10 @@ -import type { ContextApi, Layer } from 'artalk' import { JSX } from 'solid-js' import { render } from 'solid-js/web' +import type { Layer } from 'artalk' +import type { AuthContext } from '../types' -export const createLayer = (ctx: ContextApi) => { - const layer = ctx.get('layerManager').create('login') +export const createLayer = (ctx: AuthContext) => { + const layer = ctx.getLayers().create('login') const show = (el: (l: Layer) => JSX.Element) => { const $el = document.createElement('div') render(() => el(layer), $el) diff --git a/ui/plugin-auth/lib/methods.ts b/ui/plugin-auth/lib/methods.ts index 89e45cf8..01d48058 100644 --- a/ui/plugin-auth/lib/methods.ts +++ b/ui/plugin-auth/lib/methods.ts @@ -1,4 +1,4 @@ -import { ContextApi } from 'artalk' +import type { Api } from 'artalk' export interface LoginMethod { name: string @@ -8,8 +8,8 @@ export interface LoginMethod { onClick?: () => void } -export const fetchMethods = async (ctx: ContextApi) => { - const { data } = await ctx.getApi().conf.getSocialLoginProviders() +export const fetchMethods = async (api: Api) => { + const { data } = await api.conf.getSocialLoginProviders() return data.providers .map(({ name, label, icon, path }) => { return { name, label, icon, link: path } diff --git a/ui/plugin-auth/lib/oauth-login.ts b/ui/plugin-auth/lib/oauth-login.ts index 379cdf1b..da05ee64 100644 --- a/ui/plugin-auth/lib/oauth-login.ts +++ b/ui/plugin-auth/lib/oauth-login.ts @@ -1,4 +1,4 @@ -import type { ContextApi } from 'artalk' +import type { AuthContext } from '../types' let watchTimer: any = null let messageHandler: ((evt: MessageEvent) => void) | null = null @@ -8,7 +8,7 @@ const clearListener = () => { messageHandler && window.removeEventListener('message', messageHandler) } -export const startOAuthLogin = (ctx: ContextApi, url: string) => { +export const startOAuthLogin = (ctx: AuthContext, url: string) => { clearListener() const width = 1020 diff --git a/ui/plugin-auth/lib/token-login.ts b/ui/plugin-auth/lib/token-login.ts index 06695d2f..9c610e91 100644 --- a/ui/plugin-auth/lib/token-login.ts +++ b/ui/plugin-auth/lib/token-login.ts @@ -1,25 +1,26 @@ -import type { ContextApi, LocalUser } from 'artalk' +import type { LocalUser } from 'artalk' +import type { AuthContext } from '../types' interface ResponseLoginData { user: Omit token: string } -export const loginByApiRes = (ctx: ContextApi, { user, token }: ResponseLoginData) => { - ctx.get('user').update({ +export const loginByApiRes = (ctx: AuthContext, { user, token }: ResponseLoginData) => { + ctx.getUser().update({ ...user, token, }) } -export const loginByToken = (ctx: ContextApi, token: string) => { - ctx.get('user').update({ token }) +export const loginByToken = (ctx: AuthContext, token: string) => { + ctx.getUser().update({ token }) ctx .getApi() .user.getUser() .then((res) => { const { user } = res.data - ctx.get('user').update({ + ctx.getUser().update({ name: user.name, email: user.email, link: user.link, diff --git a/ui/plugin-auth/main.tsx b/ui/plugin-auth/main.tsx index 48cf2e44..32098839 100644 --- a/ui/plugin-auth/main.tsx +++ b/ui/plugin-auth/main.tsx @@ -4,33 +4,53 @@ import type { ArtalkPlugin } from 'artalk' import { DialogMain } from './DialogMain' import { createLayer } from './lib/layer' import { RenderEditorUser } from './EditorUser' +import type { AuthContext } from './types' export const ArtalkAuthPlugin: ArtalkPlugin = (ctx) => { - ctx.getApiHandlers().add('need_auth_login', () => { + const editor = ctx.inject('editor') + const api = ctx.inject('api') + const apiHandlers = ctx.inject('apiHandlers') + const user = ctx.inject('user') + const events = ctx.inject('events') + const config = ctx.inject('config') + const layers = ctx.inject('layers') + + const authCtx: AuthContext = { + getEditor: () => editor, + getApi: () => api, + getApiHandlers: () => apiHandlers, + getUser: () => user, + getEvents: () => events, + getConf: () => config, + getLayers: () => layers, + $t: (key, args) => ctx.$t(key, args), + } + + apiHandlers.add('need_auth_login', () => { openAuthDialog() throw new Error('Login required') }) let anonymous = false const refreshBtn = () => { - ctx.get('editor').getUI().$submitBtn.innerText = - ctx.get('user').getData().token || anonymous - ? ctx.conf.sendBtn || ctx.$t('send') - : ctx.$t('signIn') + editor.getUI().$submitBtn.innerText = + user.getData().token || anonymous + ? authCtx.getConf().get().sendBtn || authCtx.$t('send') + : authCtx.$t('signIn') } - ctx.watchConf(['locale', 'sendBtn'], () => refreshBtn()) - ctx.on('user-changed', () => refreshBtn()) + authCtx.getConf().watchConf(['locale', 'sendBtn'], () => refreshBtn()) + authCtx.getEvents().on('user-changed', () => refreshBtn()) - ctx.on('mounted', () => { - ctx.get('editor').getUI().$header.style.display = 'none' + authCtx.getEvents().on('mounted', () => { + editor.getUI().$header.style.display = 'none' - RenderEditorUser(ctx) + RenderEditorUser(authCtx) }) const onSkip = () => { - ctx.get('editor').getUI().$header.style.display = '' - ctx.get('editor').getUI().$name.focus() + editor.getUI().$header.style.display = '' + editor.getUI().$name.focus() ctx.updateConf({ beforeSubmit: undefined, }) @@ -40,14 +60,14 @@ export const ArtalkAuthPlugin: ArtalkPlugin = (ctx) => { } const openAuthDialog = () => { - createLayer(ctx).show((layer) => ( - layer.destroy()} onSkip={onSkip} /> + createLayer(authCtx).show((layer) => ( + layer.destroy()} onSkip={onSkip} /> )) } ctx.updateConf({ beforeSubmit: (editor, next) => { - if (!ctx.get('user').getData().token) { + if (!user.getData().token) { openAuthDialog() } else { next() diff --git a/ui/plugin-auth/merge/DialogMerge.tsx b/ui/plugin-auth/merge/DialogMerge.tsx index cce0442f..fa73f20d 100644 --- a/ui/plugin-auth/merge/DialogMerge.tsx +++ b/ui/plugin-auth/merge/DialogMerge.tsx @@ -1,10 +1,10 @@ -import type { ContextApi } from 'artalk' import { createSignal } from 'solid-js' import { Dialog } from '../Dialog' +import type { AuthContext } from '../types' import { DialogMergePageConfirm } from './DialogMergePageConfirm' interface DialogMergeProps { - ctx: ContextApi + ctx: AuthContext usernames: string[] onClose: () => void } diff --git a/ui/plugin-auth/merge/DialogMergePageConfirm.tsx b/ui/plugin-auth/merge/DialogMergePageConfirm.tsx index 78854159..8f9a10c2 100644 --- a/ui/plugin-auth/merge/DialogMergePageConfirm.tsx +++ b/ui/plugin-auth/merge/DialogMergePageConfirm.tsx @@ -1,10 +1,10 @@ import { createSignal } from 'solid-js' -import type { ContextApi } from 'artalk' import { DialogFooter } from '../DialogFooter' import { loginByToken } from '../lib/token-login' +import type { AuthContext } from '../types' interface DialogMergePageConfirmProps { - ctx: ContextApi + ctx: AuthContext usernames: string[] onClose: () => void } diff --git a/ui/plugin-auth/package.json b/ui/plugin-auth/package.json index 7c750033..58acb40f 100644 --- a/ui/plugin-auth/package.json +++ b/ui/plugin-auth/package.json @@ -1,6 +1,6 @@ { "name": "@artalk/plugin-auth", - "version": "0.0.1", + "version": "0.0.2", "license": "LGPL-3.0-only", "description": "Auth plugin for artalk", "type": "module", diff --git a/ui/plugin-auth/types/context.d.ts b/ui/plugin-auth/types/context.d.ts new file mode 100644 index 00000000..720bbaf1 --- /dev/null +++ b/ui/plugin-auth/types/context.d.ts @@ -0,0 +1,21 @@ +import type { + Api, + ApiHandlers, + ConfigManager, + Editor, + EventManager, + I18n, + LayerManager, + UserManager, +} from 'artalk' + +export interface AuthContext { + getEditor: () => Editor + getApi: () => Api + getApiHandlers: () => ApiHandlers + getUser: () => UserManager + getEvents: () => EventManager + getConf: () => ConfigManager + getLayers: () => LayerManager + $t(key: keyof I18n, args?: { [key: string]: string }): string +} diff --git a/ui/plugin-auth/types/index.d.ts b/ui/plugin-auth/types/index.d.ts new file mode 100644 index 00000000..630b4d7e --- /dev/null +++ b/ui/plugin-auth/types/index.d.ts @@ -0,0 +1 @@ +export * from './context' diff --git a/ui/plugin-kit/src/plugin/main.ts b/ui/plugin-kit/src/plugin/main.ts index 48e7e047..ede65e64 100644 --- a/ui/plugin-kit/src/plugin/main.ts +++ b/ui/plugin-kit/src/plugin/main.ts @@ -2,7 +2,7 @@ import path from 'node:path' import fs from 'node:fs' import type { LibraryOptions, Plugin } from 'vite' import ts from 'typescript' -import type { ArtalkConfigPartial } from 'artalk' +import type { ConfigPartial } from 'artalk' import { RUNTIME_PATH, getRuntimeCode, wrapVirtualPrefix } from './runtime-helper' import { getInjectHTMLTags, hijackIndexPage } from './dev-page' @@ -20,7 +20,7 @@ export interface ViteArtalkPluginKitOptions { /** * The options for Artalk instance initialization in the dev page. */ - artalkInitOptions?: ArtalkConfigPartial + artalkInitOptions?: ConfigPartial } export const ViteArtalkPluginKit = (opts: ViteArtalkPluginKitOptions = {}): Plugin => {