Compare commits
5 Commits
92eb626cb9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d89137037 | ||
|
|
74f488f242 | ||
| 92cc6e779a | |||
| c0b1e95204 | |||
| 914c98852b |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,5 +4,5 @@ node_modules/
|
|||||||
*.map
|
*.map
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.sourcemaps
|
.sourcemaps
|
||||||
dist/
|
/dist/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
@@ -465,9 +465,9 @@
|
|||||||
INFOPLIST_FILE = App/Info.plist;
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
MARKETING_VERSION = 1.0.6;
|
MARKETING_VERSION = 1.0.8;
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forumtest;
|
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forum;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -488,8 +488,8 @@
|
|||||||
INFOPLIST_FILE = App/Info.plist;
|
INFOPLIST_FILE = App/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
MARKETING_VERSION = 1.0.6;
|
MARKETING_VERSION = 1.0.8;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forumtest;
|
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forum;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -521,7 +521,7 @@
|
|||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forumtest.nse;
|
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forum.nse;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
@@ -554,7 +554,7 @@
|
|||||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forumtest.nse;
|
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forum.nse;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSUserActivityTypes</key>
|
|
||||||
<array>
|
|
||||||
<string>INSendMessageIntent</string>
|
|
||||||
</array>
|
|
||||||
<key>NSExtension</key>
|
<key>NSExtension</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionPointIdentifier</key>
|
<key>NSExtensionPointIdentifier</key>
|
||||||
@@ -13,5 +9,9 @@
|
|||||||
<key>NSExtensionPrincipalClass</key>
|
<key>NSExtensionPrincipalClass</key>
|
||||||
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
|
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>NSUserActivityTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>INSendMessageIntent</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
65
native-input/dist/esm/definitions.d.ts
vendored
Normal file
65
native-input/dist/esm/definitions.d.ts
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import type { PluginListenerHandle } from '@capacitor/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colors are CSS color strings resolved on the web side from the chat theme
|
||||||
|
* variables, so the native bar matches light/dark mode and the in-app palette.
|
||||||
|
*/
|
||||||
|
export interface NativeInputTheme {
|
||||||
|
/** Bar / text field background. From `--chat-input-bg`. */
|
||||||
|
inputBackground?: string;
|
||||||
|
/** Text + caret color. From `--chat-input-text`. */
|
||||||
|
text?: string;
|
||||||
|
/** Placeholder color. */
|
||||||
|
placeholder?: string;
|
||||||
|
/** Accent used for the "+" button. From `--accent`. */
|
||||||
|
accent?: string;
|
||||||
|
/** Send button background. From `--chat-sent-bg`. */
|
||||||
|
sendBackground?: string;
|
||||||
|
/** Send button glyph color. From `--chat-sent-text`. */
|
||||||
|
sendText?: string;
|
||||||
|
/** Whether the app is currently in dark mode (drives the glass/blur tint). */
|
||||||
|
dark?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PresentOptions {
|
||||||
|
/** Identifies the active chat so re-presents for a different chat reset text. */
|
||||||
|
chatId: string;
|
||||||
|
placeholder?: string;
|
||||||
|
/** Pre-fill text (e.g. a half-typed draft when re-mounting). */
|
||||||
|
text?: string;
|
||||||
|
/** When false, the field is read-only and the send button is disabled. */
|
||||||
|
canSend?: boolean;
|
||||||
|
theme?: NativeInputTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NativeInputPlugin {
|
||||||
|
/** Create + show the native input bar pinned above the keyboard. */
|
||||||
|
present(options: PresentOptions): Promise<void>;
|
||||||
|
/** Remove the native input bar. */
|
||||||
|
dismiss(): Promise<void>;
|
||||||
|
setText(options: { text: string }): Promise<void>;
|
||||||
|
getText(): Promise<{ text: string }>;
|
||||||
|
focus(): Promise<void>;
|
||||||
|
blur(): Promise<void>;
|
||||||
|
setPlaceholder(options: { placeholder: string }): Promise<void>;
|
||||||
|
setEnabled(options: { enabled: boolean }): Promise<void>;
|
||||||
|
setTheme(options: { theme: NativeInputTheme }): Promise<void>;
|
||||||
|
/** Hide/show without tearing down (e.g. when navigating away briefly). */
|
||||||
|
setVisible(options: { visible: boolean }): Promise<void>;
|
||||||
|
|
||||||
|
/** Fires on every text edit. */
|
||||||
|
addListener(eventName: 'inputChange', listenerFunc: (data: { text: string }) => void): Promise<PluginListenerHandle>;
|
||||||
|
/** Fires when the user taps send / hits the send key. */
|
||||||
|
addListener(eventName: 'send', listenerFunc: (data: { text: string }) => void): Promise<PluginListenerHandle>;
|
||||||
|
/** Fires when the "+" attach button is tapped. */
|
||||||
|
addListener(eventName: 'attach', listenerFunc: () => void): Promise<PluginListenerHandle>;
|
||||||
|
/** Fires on focus / blur of the native field. */
|
||||||
|
addListener(eventName: 'focusChange', listenerFunc: (data: { focused: boolean }) => void): Promise<PluginListenerHandle>;
|
||||||
|
/**
|
||||||
|
* Fires when the space the bar (and keyboard) occupies changes, in CSS px,
|
||||||
|
* so the web layout can pad its scroll area / position the reply strip.
|
||||||
|
*/
|
||||||
|
addListener(eventName: 'heightChange', listenerFunc: (data: { bottomInset: number }) => void): Promise<PluginListenerHandle>;
|
||||||
|
|
||||||
|
removeAllListeners(): Promise<void>;
|
||||||
|
}
|
||||||
1
native-input/dist/esm/definitions.js
vendored
Normal file
1
native-input/dist/esm/definitions.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {};
|
||||||
4
native-input/dist/esm/index.d.ts
vendored
Normal file
4
native-input/dist/esm/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import type { NativeInputPlugin } from './definitions';
|
||||||
|
declare const NativeInput: NativeInputPlugin;
|
||||||
|
export * from './definitions';
|
||||||
|
export { NativeInput };
|
||||||
8
native-input/dist/esm/index.js
vendored
Normal file
8
native-input/dist/esm/index.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { registerPlugin } from '@capacitor/core';
|
||||||
|
|
||||||
|
const NativeInput = registerPlugin('NativeInput', {
|
||||||
|
web: () => import('./web').then(m => new m.NativeInputWeb()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export * from './definitions';
|
||||||
|
export { NativeInput };
|
||||||
15
native-input/dist/esm/web.d.ts
vendored
Normal file
15
native-input/dist/esm/web.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { WebPlugin } from '@capacitor/core';
|
||||||
|
import type { NativeInputPlugin } from './definitions';
|
||||||
|
export declare class NativeInputWeb extends WebPlugin implements NativeInputPlugin {
|
||||||
|
present(): Promise<void>;
|
||||||
|
dismiss(): Promise<void>;
|
||||||
|
setText(): Promise<void>;
|
||||||
|
getText(): Promise<{ text: string }>;
|
||||||
|
focus(): Promise<void>;
|
||||||
|
blur(): Promise<void>;
|
||||||
|
setPlaceholder(): Promise<void>;
|
||||||
|
setEnabled(): Promise<void>;
|
||||||
|
setTheme(): Promise<void>;
|
||||||
|
setVisible(): Promise<void>;
|
||||||
|
addListener(eventName: any, listenerFunc: any): Promise<any>;
|
||||||
|
}
|
||||||
17
native-input/dist/esm/web.js
vendored
Normal file
17
native-input/dist/esm/web.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { WebPlugin } from '@capacitor/core';
|
||||||
|
|
||||||
|
// No-op web implementation so the plugin import resolves in the browser build.
|
||||||
|
// The HTML composer (textarea) is used on web; these methods are never the
|
||||||
|
// active path there, but must exist to avoid runtime crashes.
|
||||||
|
export class NativeInputWeb extends WebPlugin {
|
||||||
|
async present() { /* no-op on web */ }
|
||||||
|
async dismiss() { /* no-op on web */ }
|
||||||
|
async setText() { /* no-op on web */ }
|
||||||
|
async getText() { return { text: '' }; }
|
||||||
|
async focus() { /* no-op on web */ }
|
||||||
|
async blur() { /* no-op on web */ }
|
||||||
|
async setPlaceholder() { /* no-op on web */ }
|
||||||
|
async setEnabled() { /* no-op on web */ }
|
||||||
|
async setTheme() { /* no-op on web */ }
|
||||||
|
async setVisible() { /* no-op on web */ }
|
||||||
|
}
|
||||||
25
native-input/dist/plugin.cjs.js
vendored
Normal file
25
native-input/dist/plugin.cjs.js
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
const core = require('@capacitor/core');
|
||||||
|
|
||||||
|
class NativeInputWeb extends core.WebPlugin {
|
||||||
|
async present() {}
|
||||||
|
async dismiss() {}
|
||||||
|
async setText() {}
|
||||||
|
async getText() { return { text: '' }; }
|
||||||
|
async focus() {}
|
||||||
|
async blur() {}
|
||||||
|
async setPlaceholder() {}
|
||||||
|
async setEnabled() {}
|
||||||
|
async setTheme() {}
|
||||||
|
async setVisible() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NativeInput = core.registerPlugin('NativeInput', {
|
||||||
|
web: () => Promise.resolve(new NativeInputWeb()),
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.NativeInput = NativeInput;
|
||||||
|
exports.NativeInputWeb = NativeInputWeb;
|
||||||
65
native-sidebar/dist/esm/definitions.d.ts
vendored
Normal file
65
native-sidebar/dist/esm/definitions.d.ts
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import type { PluginListenerHandle } from '@capacitor/core';
|
||||||
|
|
||||||
|
/** A network row rendered in the sidebar. Shapes match `global.networks`. */
|
||||||
|
export interface SidebarNetwork {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
abbreviation: string;
|
||||||
|
logo?: string | null;
|
||||||
|
displayOrder?: number;
|
||||||
|
data?: {
|
||||||
|
announcements?: { text: string }[];
|
||||||
|
members?: { id: number }[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SidebarProfile {
|
||||||
|
id: number;
|
||||||
|
first_name?: string;
|
||||||
|
last_name?: string;
|
||||||
|
email?: string;
|
||||||
|
image_path?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SidebarData {
|
||||||
|
/** Origin that serves the UI (quill.js, Sidebar.js, host page). */
|
||||||
|
uiOrigin: string;
|
||||||
|
/** Origin that serves images (logos, avatars). */
|
||||||
|
serverOrigin: string;
|
||||||
|
profile: SidebarProfile;
|
||||||
|
networks: SidebarNetwork[];
|
||||||
|
currentNetworkId?: number | null;
|
||||||
|
/** Current theme key: light | parchment | dark | red. */
|
||||||
|
theme?: string;
|
||||||
|
/** Whether the current user may create networks. */
|
||||||
|
canCreateNetwork?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An action forwarded from the sidebar's content web view to the main app. */
|
||||||
|
export interface SidebarAction {
|
||||||
|
type: 'selectNetwork' | 'openProfile' | 'createNetwork' | 'setTheme' | 'logout';
|
||||||
|
abbreviation?: string;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NativeSidebarPlugin {
|
||||||
|
/** Create (pre-warm) the drawer if needed and push the latest data into it. */
|
||||||
|
setData(data: SidebarData): Promise<void>;
|
||||||
|
/** Update just the theme (key) without re-sending all data. */
|
||||||
|
setTheme(options: { theme: string }): Promise<void>;
|
||||||
|
/** Animate the drawer open. */
|
||||||
|
open(): Promise<void>;
|
||||||
|
/** Animate the drawer closed. */
|
||||||
|
close(): Promise<void>;
|
||||||
|
/** Enable/disable the edge-drag gesture (disabled on deep routes). */
|
||||||
|
setEnabled(options: { enabled: boolean }): Promise<void>;
|
||||||
|
/** Tear down the drawer entirely. */
|
||||||
|
dismiss(): Promise<void>;
|
||||||
|
|
||||||
|
/** Fires when the user taps something in the sidebar content. */
|
||||||
|
addListener(eventName: 'action', listenerFunc: (data: SidebarAction) => void): Promise<PluginListenerHandle>;
|
||||||
|
/** Fires when the drawer finishes opening/closing. */
|
||||||
|
addListener(eventName: 'stateChange', listenerFunc: (data: { open: boolean }) => void): Promise<PluginListenerHandle>;
|
||||||
|
|
||||||
|
removeAllListeners(): Promise<void>;
|
||||||
|
}
|
||||||
1
native-sidebar/dist/esm/definitions.js
vendored
Normal file
1
native-sidebar/dist/esm/definitions.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {};
|
||||||
4
native-sidebar/dist/esm/index.d.ts
vendored
Normal file
4
native-sidebar/dist/esm/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import type { NativeSidebarPlugin } from './definitions';
|
||||||
|
declare const NativeSidebar: NativeSidebarPlugin;
|
||||||
|
export * from './definitions';
|
||||||
|
export { NativeSidebar };
|
||||||
8
native-sidebar/dist/esm/index.js
vendored
Normal file
8
native-sidebar/dist/esm/index.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { registerPlugin } from '@capacitor/core';
|
||||||
|
|
||||||
|
const NativeSidebar = registerPlugin('NativeSidebar', {
|
||||||
|
web: () => import('./web').then(m => new m.NativeSidebarWeb()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export * from './definitions';
|
||||||
|
export { NativeSidebar };
|
||||||
11
native-sidebar/dist/esm/web.d.ts
vendored
Normal file
11
native-sidebar/dist/esm/web.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { WebPlugin } from '@capacitor/core';
|
||||||
|
import type { NativeSidebarPlugin } from './definitions';
|
||||||
|
export declare class NativeSidebarWeb extends WebPlugin implements NativeSidebarPlugin {
|
||||||
|
setData(): Promise<void>;
|
||||||
|
setTheme(): Promise<void>;
|
||||||
|
open(): Promise<void>;
|
||||||
|
close(): Promise<void>;
|
||||||
|
setEnabled(): Promise<void>;
|
||||||
|
dismiss(): Promise<void>;
|
||||||
|
addListener(eventName: any, listenerFunc: any): Promise<any>;
|
||||||
|
}
|
||||||
13
native-sidebar/dist/esm/web.js
vendored
Normal file
13
native-sidebar/dist/esm/web.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { WebPlugin } from '@capacitor/core';
|
||||||
|
|
||||||
|
// No-op web implementation so the plugin import resolves in the browser build.
|
||||||
|
// The drawer is iOS-native only; on web these methods are never the active path
|
||||||
|
// but must exist to avoid runtime crashes.
|
||||||
|
export class NativeSidebarWeb extends WebPlugin {
|
||||||
|
async setData() { /* no-op on web */ }
|
||||||
|
async setTheme() { /* no-op on web */ }
|
||||||
|
async open() { /* no-op on web */ }
|
||||||
|
async close() { /* no-op on web */ }
|
||||||
|
async setEnabled() { /* no-op on web */ }
|
||||||
|
async dismiss() { /* no-op on web */ }
|
||||||
|
}
|
||||||
21
native-sidebar/dist/plugin.cjs.js
vendored
Normal file
21
native-sidebar/dist/plugin.cjs.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
const core = require('@capacitor/core');
|
||||||
|
|
||||||
|
class NativeSidebarWeb extends core.WebPlugin {
|
||||||
|
async setData() {}
|
||||||
|
async setTheme() {}
|
||||||
|
async open() {}
|
||||||
|
async close() {}
|
||||||
|
async setEnabled() {}
|
||||||
|
async dismiss() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NativeSidebar = core.registerPlugin('NativeSidebar', {
|
||||||
|
web: () => Promise.resolve(new NativeSidebarWeb()),
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.NativeSidebar = NativeSidebar;
|
||||||
|
exports.NativeSidebarWeb = NativeSidebarWeb;
|
||||||
@@ -55,7 +55,6 @@ Remove the "server" object from capacitor.config.
|
|||||||
npx cap config - this will list the full configuration currently being used
|
npx cap config - this will list the full configuration currently being used
|
||||||
|
|
||||||
### Architecture
|
### Architecture
|
||||||
|
|
||||||
In Development, API routes are routed using the vite.config.js.
|
In Development, API routes are routed using the vite.config.js.
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
try {
|
try {
|
||||||
await appendStylesheet(`${window.config.UI}/_/code/shared.css`, { replaceExisting: true });
|
await appendStylesheet(`${window.config.UI}/_/code/shared.css`, { replaceExisting: true });
|
||||||
await appendScript(window.config.UI + '/_/code/quill.js')
|
await appendScript(window.config.UI + '/_/code/quill.js')
|
||||||
|
await appendScript(window.config.UI + '/_/lib/hls.min.js')
|
||||||
await appendScript(window.config.UI + '/83947261/index.js', true)
|
await appendScript(window.config.UI + '/83947261/index.js', true)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
document.body.innerHTML = `
|
document.body.innerHTML = `
|
||||||
|
|||||||
Reference in New Issue
Block a user