Frontend: Removed calckey-js autogenerated docs and integrations, reformated the entire frontend
ci/woodpecker/push/ociImagePush Pipeline failed Details

This commit is contained in:
Natty 2023-07-23 15:31:28 +02:00
parent 40c471ff56
commit 8cce5fc419
Signed by: natty
GPG Key ID: BF6CB659ADEE60EC
648 changed files with 62526 additions and 82020 deletions

View File

@ -1,364 +0,0 @@
/**
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
/**
* Optionally specifies another JSON config file that this file extends from. This provides a way for
* standard settings to be shared across multiple projects.
*
* If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains
* the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be
* resolved using NodeJS require().
*
* SUPPORTED TOKENS: none
* DEFAULT VALUE: ""
*/
// "extends": "./shared/api-extractor-base.json"
// "extends": "my-package/include/api-extractor-base.json"
/**
* Determines the "<projectFolder>" token that can be used with other config file settings. The project folder
* typically contains the tsconfig.json and package.json config files, but the path is user-defined.
*
* The path is resolved relative to the folder of the config file that contains the setting.
*
* The default value for "projectFolder" is the token "<lookup>", which means the folder is determined by traversing
* parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder
* that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error
* will be reported.
*
* SUPPORTED TOKENS: <lookup>
* DEFAULT VALUE: "<lookup>"
*/
// "projectFolder": "..",
/**
* (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
* analyzes the symbols exported by this module.
*
* The file extension must be ".d.ts" and not ".ts".
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
*/
"mainEntryPointFilePath": "<projectFolder>/built/index.d.ts",
/**
* A list of NPM package names whose exports should be treated as part of this package.
*
* For example, suppose that Webpack is used to generate a distributed bundle for the project "library1",
* and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part
* of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly
* imports library2. To avoid this, we can specify:
*
* "bundledPackages": [ "library2" ],
*
* This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been
* local files for library1.
*/
"bundledPackages": [],
/**
* Determines how the TypeScript compiler engine will be invoked by API Extractor.
*/
"compiler": {
/**
* Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* Note: This setting will be ignored if "overrideTsconfig" is used.
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
* DEFAULT VALUE: "<projectFolder>/tsconfig.json"
*/
// "tsconfigFilePath": "<projectFolder>/tsconfig.json",
/**
* Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.
* The object must conform to the TypeScript tsconfig schema:
*
* http://json.schemastore.org/tsconfig
*
* If omitted, then the tsconfig.json file will be read from the "projectFolder".
*
* DEFAULT VALUE: no overrideTsconfig section
*/
// "overrideTsconfig": {
// . . .
// }
/**
* This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended
* and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when
* dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses
* for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.
*
* DEFAULT VALUE: false
*/
// "skipLibCheck": true,
},
/**
* Configures how the API report file (*.api.md) will be generated.
*/
"apiReport": {
/**
* (REQUIRED) Whether to generate an API report.
*/
"enabled": true
/**
* The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce
* a full file path.
*
* The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/".
*
* SUPPORTED TOKENS: <packageName>, <unscopedPackageName>
* DEFAULT VALUE: "<unscopedPackageName>.api.md"
*/
// "reportFileName": "<unscopedPackageName>.api.md",
/**
* Specifies the folder where the API report file is written. The file name portion is determined by
* the "reportFileName" setting.
*
* The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy,
* e.g. for an API review.
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
* DEFAULT VALUE: "<projectFolder>/etc/"
*/
// "reportFolder": "<projectFolder>/etc/",
/**
* Specifies the folder where the temporary report file is written. The file name portion is determined by
* the "reportFileName" setting.
*
* After the temporary file is written to disk, it is compared with the file in the "reportFolder".
* If they are different, a production build will fail.
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
* DEFAULT VALUE: "<projectFolder>/temp/"
*/
// "reportTempFolder": "<projectFolder>/temp/"
},
/**
* Configures how the doc model file (*.api.json) will be generated.
*/
"docModel": {
/**
* (REQUIRED) Whether to generate a doc model file.
*/
"enabled": true
/**
* The output path for the doc model file. The file extension should be ".api.json".
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
* DEFAULT VALUE: "<projectFolder>/temp/<unscopedPackageName>.api.json"
*/
// "apiJsonFilePath": "<projectFolder>/temp/<unscopedPackageName>.api.json"
},
/**
* Configures how the .d.ts rollup file will be generated.
*/
"dtsRollup": {
/**
* (REQUIRED) Whether to generate the .d.ts rollup file.
*/
"enabled": false
/**
* Specifies the output path for a .d.ts rollup file to be generated without any trimming.
* This file will include all declarations that are exported by the main entry point.
*
* If the path is an empty string, then this file will not be written.
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
* DEFAULT VALUE: "<projectFolder>/dist/<unscopedPackageName>.d.ts"
*/
// "untrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>.d.ts",
/**
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release.
* This file will include only declarations that are marked as "@public" or "@beta".
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
* DEFAULT VALUE: ""
*/
// "betaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-beta.d.ts",
/**
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release.
* This file will include only declarations that are marked as "@public".
*
* If the path is an empty string, then this file will not be written.
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
* DEFAULT VALUE: ""
*/
// "publicTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-public.d.ts",
/**
* When a declaration is trimmed, by default it will be replaced by a code comment such as
* "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the
* declaration completely.
*
* DEFAULT VALUE: false
*/
// "omitTrimmingComments": true
},
/**
* Configures how the tsdoc-metadata.json file will be generated.
*/
"tsdocMetadata": {
/**
* Whether to generate the tsdoc-metadata.json file.
*
* DEFAULT VALUE: true
*/
// "enabled": true,
/**
* Specifies where the TSDoc metadata file should be written.
*
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
* prepend a folder token such as "<projectFolder>".
*
* The default value is "<lookup>", which causes the path to be automatically inferred from the "tsdocMetadata",
* "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup
* falls back to "tsdoc-metadata.json" in the package folder.
*
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
* DEFAULT VALUE: "<lookup>"
*/
// "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json"
},
/**
* Specifies what type of newlines API Extractor should use when writing output files. By default, the output files
* will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead.
* To use the OS's default newline kind, specify "os".
*
* DEFAULT VALUE: "crlf"
*/
// "newlineKind": "crlf",
/**
* Configures how API Extractor reports error and warning messages produced during analysis.
*
* There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages.
*/
"messages": {
/**
* Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing
* the input .d.ts files.
*
* TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551"
*
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
*/
"compilerMessageReporting": {
/**
* Configures the default routing for messages that don't match an explicit rule in this table.
*/
"default": {
/**
* Specifies whether the message should be written to the the tool's output log. Note that
* the "addToApiReportFile" property may supersede this option.
*
* Possible values: "error", "warning", "none"
*
* Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail
* and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes
* the "--local" option), the warning is displayed but the build will not fail.
*
* DEFAULT VALUE: "warning"
*/
"logLevel": "warning"
/**
* When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md),
* then the message will be written inside that file; otherwise, the message is instead logged according to
* the "logLevel" option.
*
* DEFAULT VALUE: false
*/
// "addToApiReportFile": false
}
// "TS2551": {
// "logLevel": "warning",
// "addToApiReportFile": true
// },
//
// . . .
},
/**
* Configures handling of messages reported by API Extractor during its analysis.
*
* API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag"
*
* DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings
*/
"extractorMessageReporting": {
"default": {
"logLevel": "none"
// "addToApiReportFile": false
}
// "ae-extra-release-tag": {
// "logLevel": "warning",
// "addToApiReportFile": true
// },
//
// . . .
},
/**
* Configures handling of messages reported by the TSDoc parser when analyzing code comments.
*
* TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text"
*
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
*/
"tsdocMessageReporting": {
"default": {
"logLevel": "warning"
// "addToApiReportFile": false
}
// "tsdoc-link-tag-unescaped-text": {
// "logLevel": "warning",
// "addToApiReportFile": true
// },
//
// . . .
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Acct](./calckey-js.acct.md)
## Acct type
**Signature:**
```typescript
export declare type Acct = {
username: string;
host: string | null;
};
```

View File

@ -1,24 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [APIClient](./calckey-js.api.apiclient.md) &gt; [(constructor)](./calckey-js.api.apiclient._constructor_.md)
## api.APIClient.(constructor)
Constructs a new instance of the `APIClient` class
**Signature:**
```typescript
constructor(opts: {
origin: APIClient["origin"];
credential?: APIClient["credential"];
fetch?: APIClient["fetch"] | null | undefined;
});
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| opts | { origin: [APIClient](./calckey-js.api.apiclient.md)<!-- -->\["origin"\]; credential?: [APIClient](./calckey-js.api.apiclient.md)<!-- -->\["credential"\]; fetch?: [APIClient](./calckey-js.api.apiclient.md)<!-- -->\["fetch"\] \| null \| undefined; } | |

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [APIClient](./calckey-js.api.apiclient.md) &gt; [credential](./calckey-js.api.apiclient.credential.md)
## api.APIClient.credential property
**Signature:**
```typescript
credential: string | null | undefined;
```

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [APIClient](./calckey-js.api.apiclient.md) &gt; [fetch](./calckey-js.api.apiclient.fetch.md)
## api.APIClient.fetch property
**Signature:**
```typescript
fetch: FetchLike;
```

View File

@ -1,32 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [APIClient](./calckey-js.api.apiclient.md)
## api.APIClient class
**Signature:**
```typescript
export declare class APIClient
```
## Constructors
| Constructor | Modifiers | Description |
| --- | --- | --- |
| [(constructor)(opts)](./calckey-js.api.apiclient._constructor_.md) | | Constructs a new instance of the <code>APIClient</code> class |
## Properties
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [credential](./calckey-js.api.apiclient.credential.md) | | string \| null \| undefined | |
| [fetch](./calckey-js.api.apiclient.fetch.md) | | [FetchLike](./calckey-js.api.fetchlike.md) | |
| [origin](./calckey-js.api.apiclient.origin.md) | | string | |
## Methods
| Method | Modifiers | Description |
| --- | --- | --- |
| [request(endpoint, params, credential)](./calckey-js.api.apiclient.request.md) | | |

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [APIClient](./calckey-js.api.apiclient.md) &gt; [origin](./calckey-js.api.apiclient.origin.md)
## api.APIClient.origin property
**Signature:**
```typescript
origin: string;
```

View File

@ -1,57 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [APIClient](./calckey-js.api.apiclient.md) &gt; [request](./calckey-js.api.apiclient.request.md)
## api.APIClient.request() method
**Signature:**
```typescript
request<E extends keyof Endpoints, P extends Endpoints[E]["req"]>(
endpoint: E,
params?: P,
credential?: string | null | undefined,
): Promise<
Endpoints[E]["res"] extends {
$switch: {
$cases: [any, any][];
$default: any;
};
}
? IsCaseMatched<E, P, 0> extends true
? GetCaseResult<E, P, 0>
: IsCaseMatched<E, P, 1> extends true
? GetCaseResult<E, P, 1>
: IsCaseMatched<E, P, 2> extends true
? GetCaseResult<E, P, 2>
: IsCaseMatched<E, P, 3> extends true
? GetCaseResult<E, P, 3>
: IsCaseMatched<E, P, 4> extends true
? GetCaseResult<E, P, 4>
: IsCaseMatched<E, P, 5> extends true
? GetCaseResult<E, P, 5>
: IsCaseMatched<E, P, 6> extends true
? GetCaseResult<E, P, 6>
: IsCaseMatched<E, P, 7> extends true
? GetCaseResult<E, P, 7>
: IsCaseMatched<E, P, 8> extends true
? GetCaseResult<E, P, 8>
: IsCaseMatched<E, P, 9> extends true
? GetCaseResult<E, P, 9>
: Endpoints[E]["res"]["$switch"]["$default"]
: Endpoints[E]["res"]
>;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| endpoint | E | |
| params | P | _(Optional)_ |
| credential | string \| null \| undefined | _(Optional)_ |
**Returns:**
Promise&lt; [Endpoints](./calckey-js.endpoints.md)<!-- -->\[E\]\["res"\] extends { $switch: { $cases: \[any, any\]\[\]; $default: any; }; } ? IsCaseMatched&lt;E, P, 0&gt; extends true ? GetCaseResult&lt;E, P, 0&gt; : IsCaseMatched&lt;E, P, 1&gt; extends true ? GetCaseResult&lt;E, P, 1&gt; : IsCaseMatched&lt;E, P, 2&gt; extends true ? GetCaseResult&lt;E, P, 2&gt; : IsCaseMatched&lt;E, P, 3&gt; extends true ? GetCaseResult&lt;E, P, 3&gt; : IsCaseMatched&lt;E, P, 4&gt; extends true ? GetCaseResult&lt;E, P, 4&gt; : IsCaseMatched&lt;E, P, 5&gt; extends true ? GetCaseResult&lt;E, P, 5&gt; : IsCaseMatched&lt;E, P, 6&gt; extends true ? GetCaseResult&lt;E, P, 6&gt; : IsCaseMatched&lt;E, P, 7&gt; extends true ? GetCaseResult&lt;E, P, 7&gt; : IsCaseMatched&lt;E, P, 8&gt; extends true ? GetCaseResult&lt;E, P, 8&gt; : IsCaseMatched&lt;E, P, 9&gt; extends true ? GetCaseResult&lt;E, P, 9&gt; : [Endpoints](./calckey-js.endpoints.md)<!-- -->\[E\]\["res"\]\["$switch"\]\["$default"\] : [Endpoints](./calckey-js.endpoints.md)<!-- -->\[E\]\["res"\] &gt;

View File

@ -1,17 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [APIError](./calckey-js.api.apierror.md)
## api.APIError type
**Signature:**
```typescript
export declare type APIError = {
id: string;
code: string;
message: string;
kind: "client" | "server";
info: Record<string, any>;
};
```

View File

@ -1,22 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [FetchLike](./calckey-js.api.fetchlike.md)
## api.FetchLike type
**Signature:**
```typescript
export declare type FetchLike = (
input: string,
init?: {
method?: string;
body?: string;
credentials?: RequestCredentials;
cache?: RequestCache;
},
) => Promise<{
status: number;
json(): Promise<any>;
}>;
```

View File

@ -1,22 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md) &gt; [isAPIError](./calckey-js.api.isapierror.md)
## api.isAPIError() function
**Signature:**
```typescript
export declare function isAPIError(reason: any): reason is APIError;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| reason | any | |
**Returns:**
reason is [APIError](./calckey-js.api.apierror.md)

View File

@ -1,25 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [api](./calckey-js.api.md)
## api namespace
## Classes
| Class | Description |
| --- | --- |
| [APIClient](./calckey-js.api.apiclient.md) | |
## Functions
| Function | Description |
| --- | --- |
| [isAPIError(reason)](./calckey-js.api.isapierror.md) | |
## Type Aliases
| Type Alias | Description |
| --- | --- |
| [APIError](./calckey-js.api.apierror.md) | |
| [FetchLike](./calckey-js.api.fetchlike.md) | |

View File

@ -1,22 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [(constructor)](./calckey-js.channelconnection._constructor_.md)
## ChannelConnection.(constructor)
Constructs a new instance of the `Connection` class
**Signature:**
```typescript
constructor(stream: Stream, channel: string, name?: string);
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| stream | [Stream](./calckey-js.stream.md) | |
| channel | string | |
| name | string | _(Optional)_ |

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [channel](./calckey-js.channelconnection.channel.md)
## ChannelConnection.channel property
**Signature:**
```typescript
channel: string;
```

View File

@ -1,15 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [dispose](./calckey-js.channelconnection.dispose.md)
## ChannelConnection.dispose() method
**Signature:**
```typescript
abstract dispose(): void;
```
**Returns:**
void

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [id](./calckey-js.channelconnection.id.md)
## ChannelConnection.id property
**Signature:**
```typescript
abstract id: string;
```

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [inCount](./calckey-js.channelconnection.incount.md)
## ChannelConnection.inCount property
**Signature:**
```typescript
inCount: number;
```

View File

@ -1,39 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md)
## ChannelConnection class
**Signature:**
```typescript
export declare abstract class Connection<
Channel extends AnyOf<Channels> = any,
> extends EventEmitter<Channel["events"]>
```
**Extends:** EventEmitter&lt;Channel\["events"\]&gt;
## Constructors
| Constructor | Modifiers | Description |
| --- | --- | --- |
| [(constructor)(stream, channel, name)](./calckey-js.channelconnection._constructor_.md) | | Constructs a new instance of the <code>Connection</code> class |
## Properties
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [channel](./calckey-js.channelconnection.channel.md) | | string | |
| [id](./calckey-js.channelconnection.id.md) | <code>abstract</code> | string | |
| [inCount](./calckey-js.channelconnection.incount.md) | | number | |
| [name?](./calckey-js.channelconnection.name.md) | | string | _(Optional)_ |
| [outCount](./calckey-js.channelconnection.outcount.md) | | number | |
| [stream](./calckey-js.channelconnection.stream.md) | <code>protected</code> | [Stream](./calckey-js.stream.md) | |
## Methods
| Method | Modifiers | Description |
| --- | --- | --- |
| [dispose()](./calckey-js.channelconnection.dispose.md) | <code>abstract</code> | |
| [send(type, body)](./calckey-js.channelconnection.send.md) | | |

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [name](./calckey-js.channelconnection.name.md)
## ChannelConnection.name property
**Signature:**
```typescript
name?: string;
```

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [outCount](./calckey-js.channelconnection.outcount.md)
## ChannelConnection.outCount property
**Signature:**
```typescript
outCount: number;
```

View File

@ -1,26 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [send](./calckey-js.channelconnection.send.md)
## ChannelConnection.send() method
**Signature:**
```typescript
send<T extends keyof Channel["receives"]>(
type: T,
body: Channel["receives"][T],
): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| type | T | |
| body | Channel\["receives"\]\[T\] | |
**Returns:**
void

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ChannelConnection](./calckey-js.channelconnection.md) &gt; [stream](./calckey-js.channelconnection.stream.md)
## ChannelConnection.stream property
**Signature:**
```typescript
protected stream: Stream;
```

View File

@ -1,143 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Channels](./calckey-js.channels.md)
## Channels type
**Signature:**
```typescript
export declare type Channels = {
main: {
params: null;
events: {
notification: (payload: Notification) => void;
mention: (payload: Note) => void;
reply: (payload: Note) => void;
renote: (payload: Note) => void;
follow: (payload: User) => void;
followed: (payload: User) => void;
unfollow: (payload: User) => void;
meUpdated: (payload: MeDetailed) => void;
pageEvent: (payload: PageEvent) => void;
urlUploadFinished: (payload: {
marker: string;
file: DriveFile;
}) => void;
readAllNotifications: () => void;
unreadNotification: (payload: Notification) => void;
unreadMention: (payload: Note["id"]) => void;
readAllUnreadMentions: () => void;
unreadSpecifiedNote: (payload: Note["id"]) => void;
readAllUnreadSpecifiedNotes: () => void;
readAllMessagingMessages: () => void;
messagingMessage: (payload: MessagingMessage) => void;
unreadMessagingMessage: (payload: MessagingMessage) => void;
readAllAntennas: () => void;
unreadAntenna: (payload: Antenna) => void;
readAllAnnouncements: () => void;
readAllChannels: () => void;
unreadChannel: (payload: Note["id"]) => void;
myTokenRegenerated: () => void;
reversiNoInvites: () => void;
reversiInvited: (payload: FIXME) => void;
signin: (payload: FIXME) => void;
registryUpdated: (payload: {
scope?: string[];
key: string;
value: any | null;
}) => void;
driveFileCreated: (payload: DriveFile) => void;
readAntenna: (payload: Antenna) => void;
};
receives: null;
};
homeTimeline: {
params: null;
events: {
note: (payload: Note) => void;
};
receives: null;
};
localTimeline: {
params: null;
events: {
note: (payload: Note) => void;
};
receives: null;
};
hybridTimeline: {
params: null;
events: {
note: (payload: Note) => void;
};
receives: null;
};
recommendedTimeline: {
params: null;
events: {
note: (payload: Note) => void;
};
receives: null;
};
globalTimeline: {
params: null;
events: {
note: (payload: Note) => void;
};
receives: null;
};
antenna: {
params: {
antennaId: Antenna["id"];
};
events: {
note: (payload: Note) => void;
};
receives: null;
};
messaging: {
params: {
otherparty?: User["id"] | null;
group?: UserGroup["id"] | null;
};
events: {
message: (payload: MessagingMessage) => void;
deleted: (payload: MessagingMessage["id"]) => void;
read: (payload: MessagingMessage["id"][]) => void;
typers: (payload: User[]) => void;
};
receives: {
read: {
id: MessagingMessage["id"];
};
};
};
serverStats: {
params: null;
events: {
stats: (payload: FIXME) => void;
};
receives: {
requestLog: {
id: string | number;
length: number;
};
};
};
queueStats: {
params: null;
events: {
stats: (payload: FIXME) => void;
};
receives: {
requestLog: {
id: string | number;
length: number;
};
};
};
};
```
**References:** [Note](./calckey-js.entities.note.md)<!-- -->, [User](./calckey-js.entities.user.md)<!-- -->, [MeDetailed](./calckey-js.entities.medetailed.md)<!-- -->, [PageEvent](./calckey-js.entities.pageevent.md)<!-- -->, [DriveFile](./calckey-js.entities.drivefile.md)<!-- -->, [MessagingMessage](./calckey-js.entities.messagingmessage.md)<!-- -->, [Antenna](./calckey-js.entities.antenna.md)<!-- -->, [UserGroup](./calckey-js.entities.usergroup.md)

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Ad](./calckey-js.entities.ad.md)
## entities.Ad type
**Signature:**
```typescript
export declare type Ad = TODO;
```

View File

@ -1,21 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Announcement](./calckey-js.entities.announcement.md)
## entities.Announcement type
**Signature:**
```typescript
export declare type Announcement = {
id: ID;
createdAt: DateString;
updatedAt: DateString | null;
text: string;
title: string;
imageUrl: string | null;
isRead?: boolean;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)

View File

@ -1,29 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Antenna](./calckey-js.entities.antenna.md)
## entities.Antenna type
**Signature:**
```typescript
export declare type Antenna = {
id: ID;
createdAt: DateString;
name: string;
keywords: string[][];
excludeKeywords: string[][];
src: "home" | "all" | "users" | "list" | "group" | "instances";
userListId: ID | null;
userGroupId: ID | null;
users: string[];
instances: string[];
caseSensitive: boolean;
notify: boolean;
withReplies: boolean;
withFile: boolean;
hasUnreadNote: boolean;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [App](./calckey-js.entities.app.md)
## entities.App type
**Signature:**
```typescript
export declare type App = TODO;
```

View File

@ -1,17 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [AuthSession](./calckey-js.entities.authsession.md)
## entities.AuthSession type
**Signature:**
```typescript
export declare type AuthSession = {
id: ID;
app: App;
token: string;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [App](./calckey-js.entities.app.md)

View File

@ -1,18 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Blocking](./calckey-js.entities.blocking.md)
## entities.Blocking type
**Signature:**
```typescript
export declare type Blocking = {
id: ID;
createdAt: DateString;
blockeeId: User["id"];
blockee: UserDetailed;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [User](./calckey-js.entities.user.md)<!-- -->, [UserDetailed](./calckey-js.entities.userdetailed.md)

View File

@ -1,15 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Channel](./calckey-js.entities.channel.md)
## entities.Channel type
**Signature:**
```typescript
export declare type Channel = {
id: ID;
};
```
**References:** [ID](./calckey-js.entities.id.md)

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Clip](./calckey-js.entities.clip.md)
## entities.Clip type
**Signature:**
```typescript
export declare type Clip = TODO;
```

View File

@ -1,17 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [CustomEmoji](./calckey-js.entities.customemoji.md)
## entities.CustomEmoji type
**Signature:**
```typescript
export declare type CustomEmoji = {
id: string;
name: string;
url: string;
category: string;
aliases: string[];
};
```

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [DateString](./calckey-js.entities.datestring.md)
## entities.DateString type
**Signature:**
```typescript
export declare type DateString = string;
```

View File

@ -1,15 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [DetailedInstanceMetadata](./calckey-js.entities.detailedinstancemetadata.md)
## entities.DetailedInstanceMetadata type
**Signature:**
```typescript
export declare type DetailedInstanceMetadata = LiteInstanceMetadata & {
features: Record<string, any>;
};
```
**References:** [LiteInstanceMetadata](./calckey-js.entities.liteinstancemetadata.md)

View File

@ -1,26 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [DriveFile](./calckey-js.entities.drivefile.md)
## entities.DriveFile type
**Signature:**
```typescript
export declare type DriveFile = {
id: ID;
createdAt: DateString;
isSensitive: boolean;
name: string;
thumbnailUrl: string;
url: string;
type: string;
size: number;
md5: string;
blurhash: string;
comment: string | null;
properties: Record<string, any>;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [DriveFolder](./calckey-js.entities.drivefolder.md)
## entities.DriveFolder type
**Signature:**
```typescript
export declare type DriveFolder = TODO;
```

View File

@ -1,18 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Following](./calckey-js.entities.following.md)
## entities.Following type
**Signature:**
```typescript
export declare type Following = {
id: ID;
createdAt: DateString;
followerId: User["id"];
followeeId: User["id"];
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [User](./calckey-js.entities.user.md)

View File

@ -1,15 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [FollowingFolloweePopulated](./calckey-js.entities.followingfolloweepopulated.md)
## entities.FollowingFolloweePopulated type
**Signature:**
```typescript
export declare type FollowingFolloweePopulated = Following & {
followee: UserDetailed;
};
```
**References:** [Following](./calckey-js.entities.following.md)<!-- -->, [UserDetailed](./calckey-js.entities.userdetailed.md)

View File

@ -1,15 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [FollowingFollowerPopulated](./calckey-js.entities.followingfollowerpopulated.md)
## entities.FollowingFollowerPopulated type
**Signature:**
```typescript
export declare type FollowingFollowerPopulated = Following & {
follower: UserDetailed;
};
```
**References:** [Following](./calckey-js.entities.following.md)<!-- -->, [UserDetailed](./calckey-js.entities.userdetailed.md)

View File

@ -1,17 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [FollowRequest](./calckey-js.entities.followrequest.md)
## entities.FollowRequest type
**Signature:**
```typescript
export declare type FollowRequest = {
id: ID;
follower: User;
followee: User;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [User](./calckey-js.entities.user.md)

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [GalleryPost](./calckey-js.entities.gallerypost.md)
## entities.GalleryPost type
**Signature:**
```typescript
export declare type GalleryPost = TODO;
```

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [ID](./calckey-js.entities.id.md)
## entities.ID type
**Signature:**
```typescript
export declare type ID = string;
```

View File

@ -1,40 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Instance](./calckey-js.entities.instance.md)
## entities.Instance type
**Signature:**
```typescript
export declare type Instance = {
id: ID;
caughtAt: DateString;
host: string;
usersCount: number;
notesCount: number;
followingCount: number;
followersCount: number;
driveUsage: number;
driveFiles: number;
latestRequestSentAt: DateString | null;
latestStatus: number | null;
latestRequestReceivedAt: DateString | null;
lastCommunicatedAt: DateString;
isNotResponding: boolean;
isSuspended: boolean;
softwareName: string | null;
softwareVersion: string | null;
openRegistrations: boolean | null;
name: string | null;
description: string | null;
maintainerName: string | null;
maintainerEmail: string | null;
iconUrl: string | null;
faviconUrl: string | null;
themeColor: string | null;
infoUpdatedAt: DateString | null;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)

View File

@ -1,15 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [InstanceMetadata](./calckey-js.entities.instancemetadata.md)
## entities.InstanceMetadata type
**Signature:**
```typescript
export declare type InstanceMetadata =
| LiteInstanceMetadata
| DetailedInstanceMetadata;
```
**References:** [LiteInstanceMetadata](./calckey-js.entities.liteinstancemetadata.md)<!-- -->, [DetailedInstanceMetadata](./calckey-js.entities.detailedinstancemetadata.md)

View File

@ -1,46 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [LiteInstanceMetadata](./calckey-js.entities.liteinstancemetadata.md)
## entities.LiteInstanceMetadata type
**Signature:**
```typescript
export declare type LiteInstanceMetadata = {
maintainerName: string | null;
maintainerEmail: string | null;
version: string;
name: string | null;
uri: string;
description: string | null;
tosUrl: string | null;
disableRegistration: boolean;
disableLocalTimeline: boolean;
disableRecommendedTimeline: boolean;
disableGlobalTimeline: boolean;
driveCapacityPerLocalUserMb: number;
driveCapacityPerRemoteUserMb: number;
enableHcaptcha: boolean;
hcaptchaSiteKey: string | null;
enableRecaptcha: boolean;
recaptchaSiteKey: string | null;
swPublickey: string | null;
maxNoteTextLength: number;
enableEmail: boolean;
enableTwitterIntegration: boolean;
enableGithubIntegration: boolean;
enableDiscordIntegration: boolean;
enableServiceWorker: boolean;
emojis: CustomEmoji[];
ads: {
id: ID;
ratio: number;
place: string;
url: string;
imageUrl: string;
}[];
};
```
**References:** [CustomEmoji](./calckey-js.entities.customemoji.md)<!-- -->, [ID](./calckey-js.entities.id.md)

View File

@ -1,51 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md)
## entities namespace
## Type Aliases
| Type Alias | Description |
| --- | --- |
| [Ad](./calckey-js.entities.ad.md) | |
| [Announcement](./calckey-js.entities.announcement.md) | |
| [Antenna](./calckey-js.entities.antenna.md) | |
| [App](./calckey-js.entities.app.md) | |
| [AuthSession](./calckey-js.entities.authsession.md) | |
| [Blocking](./calckey-js.entities.blocking.md) | |
| [Channel](./calckey-js.entities.channel.md) | |
| [Clip](./calckey-js.entities.clip.md) | |
| [CustomEmoji](./calckey-js.entities.customemoji.md) | |
| [DateString](./calckey-js.entities.datestring.md) | |
| [DetailedInstanceMetadata](./calckey-js.entities.detailedinstancemetadata.md) | |
| [DriveFile](./calckey-js.entities.drivefile.md) | |
| [DriveFolder](./calckey-js.entities.drivefolder.md) | |
| [Following](./calckey-js.entities.following.md) | |
| [FollowingFolloweePopulated](./calckey-js.entities.followingfolloweepopulated.md) | |
| [FollowingFollowerPopulated](./calckey-js.entities.followingfollowerpopulated.md) | |
| [FollowRequest](./calckey-js.entities.followrequest.md) | |
| [GalleryPost](./calckey-js.entities.gallerypost.md) | |
| [ID](./calckey-js.entities.id.md) | |
| [Instance](./calckey-js.entities.instance.md) | |
| [InstanceMetadata](./calckey-js.entities.instancemetadata.md) | |
| [LiteInstanceMetadata](./calckey-js.entities.liteinstancemetadata.md) | |
| [MeDetailed](./calckey-js.entities.medetailed.md) | |
| [MessagingMessage](./calckey-js.entities.messagingmessage.md) | |
| [Note](./calckey-js.entities.note.md) | |
| [NoteFavorite](./calckey-js.entities.notefavorite.md) | |
| [NoteReaction](./calckey-js.entities.notereaction.md) | |
| [Notification](./calckey-js.entities.notification.md) | |
| [OriginType](./calckey-js.entities.origintype.md) | |
| [Page](./calckey-js.entities.page.md) | |
| [PageEvent](./calckey-js.entities.pageevent.md) | |
| [ServerInfo](./calckey-js.entities.serverinfo.md) | |
| [Signin](./calckey-js.entities.signin.md) | |
| [Stats](./calckey-js.entities.stats.md) | |
| [User](./calckey-js.entities.user.md) | |
| [UserDetailed](./calckey-js.entities.userdetailed.md) | |
| [UserGroup](./calckey-js.entities.usergroup.md) | |
| [UserList](./calckey-js.entities.userlist.md) | |
| [UserLite](./calckey-js.entities.userlite.md) | |
| [UserSorting](./calckey-js.entities.usersorting.md) | |

View File

@ -1,40 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [MeDetailed](./calckey-js.entities.medetailed.md)
## entities.MeDetailed type
**Signature:**
```typescript
export declare type MeDetailed = UserDetailed & {
avatarId: DriveFile["id"];
bannerId: DriveFile["id"];
autoAcceptFollowed: boolean;
alwaysMarkNsfw: boolean;
carefulBot: boolean;
emailNotificationTypes: string[];
hasPendingReceivedFollowRequest: boolean;
hasUnreadAnnouncement: boolean;
hasUnreadAntenna: boolean;
hasUnreadChannel: boolean;
hasUnreadMentions: boolean;
hasUnreadMessagingMessage: boolean;
hasUnreadNotification: boolean;
hasUnreadSpecifiedNotes: boolean;
hideOnlineStatus: boolean;
injectFeaturedNote: boolean;
integrations: Record<string, any>;
isDeleted: boolean;
isExplorable: boolean;
mutedWords: string[][];
mutingNotificationTypes: string[];
noCrawle: boolean;
preventAiLearning: boolean;
receiveAnnouncementEmail: boolean;
usePasswordLessLogin: boolean;
[other: string]: any;
};
```
**References:** [UserDetailed](./calckey-js.entities.userdetailed.md)<!-- -->, [DriveFile](./calckey-js.entities.drivefile.md)

View File

@ -1,27 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [MessagingMessage](./calckey-js.entities.messagingmessage.md)
## entities.MessagingMessage type
**Signature:**
```typescript
export declare type MessagingMessage = {
id: ID;
createdAt: DateString;
file: DriveFile | null;
fileId: DriveFile["id"] | null;
isRead: boolean;
reads: User["id"][];
text: string | null;
user: User;
userId: User["id"];
recipient?: User | null;
recipientId: User["id"] | null;
group?: UserGroup | null;
groupId: UserGroup["id"] | null;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [DriveFile](./calckey-js.entities.drivefile.md)<!-- -->, [User](./calckey-js.entities.user.md)<!-- -->, [UserGroup](./calckey-js.entities.usergroup.md)

View File

@ -1,51 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Note](./calckey-js.entities.note.md)
## entities.Note type
**Signature:**
```typescript
export declare type Note = {
id: ID;
createdAt: DateString;
text: string | null;
cw: string | null;
user: User;
userId: User["id"];
reply?: Note;
replyId: Note["id"];
renote?: Note;
renoteId: Note["id"];
files: DriveFile[];
fileIds: DriveFile["id"][];
visibility: "public" | "home" | "followers" | "specified";
visibleUserIds?: User["id"][];
localOnly?: boolean;
channel?: Channel["id"];
myReaction?: string;
reactions: Record<string, number>;
renoteCount: number;
repliesCount: number;
poll?: {
expiresAt: DateString | null;
multiple: boolean;
choices: {
isVoted: boolean;
text: string;
votes: number;
}[];
};
emojis: {
name: string;
url: string;
}[];
uri?: string;
url?: string;
updatedAt?: DateString;
isHidden?: boolean;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [User](./calckey-js.entities.user.md)<!-- -->, [Note](./calckey-js.entities.note.md)<!-- -->, [DriveFile](./calckey-js.entities.drivefile.md)<!-- -->, [Channel](./calckey-js.entities.channel.md)

View File

@ -1,18 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [NoteFavorite](./calckey-js.entities.notefavorite.md)
## entities.NoteFavorite type
**Signature:**
```typescript
export declare type NoteFavorite = {
id: ID;
createdAt: DateString;
noteId: Note["id"];
note: Note;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [Note](./calckey-js.entities.note.md)

View File

@ -1,18 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [NoteReaction](./calckey-js.entities.notereaction.md)
## entities.NoteReaction type
**Signature:**
```typescript
export declare type NoteReaction = {
id: ID;
createdAt: DateString;
user: UserLite;
type: string;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [UserLite](./calckey-js.entities.userlite.md)

View File

@ -1,82 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Notification](./calckey-js.entities.notification.md)
## entities.Notification type
**Signature:**
```typescript
export declare type Notification = {
id: ID;
createdAt: DateString;
isRead: boolean;
} & (
| {
type: "reaction";
reaction: string;
user: User;
userId: User["id"];
note: Note;
}
| {
type: "reply";
user: User;
userId: User["id"];
note: Note;
}
| {
type: "renote";
user: User;
userId: User["id"];
note: Note;
}
| {
type: "quote";
user: User;
userId: User["id"];
note: Note;
}
| {
type: "mention";
user: User;
userId: User["id"];
note: Note;
}
| {
type: "pollVote";
user: User;
userId: User["id"];
note: Note;
}
| {
type: "follow";
user: User;
userId: User["id"];
}
| {
type: "followRequestAccepted";
user: User;
userId: User["id"];
}
| {
type: "receiveFollowRequest";
user: User;
userId: User["id"];
}
| {
type: "groupInvited";
invitation: UserGroup;
user: User;
userId: User["id"];
}
| {
type: "app";
header?: string | null;
body: string;
icon?: string | null;
}
);
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [User](./calckey-js.entities.user.md)<!-- -->, [Note](./calckey-js.entities.note.md)<!-- -->, [UserGroup](./calckey-js.entities.usergroup.md)

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [OriginType](./calckey-js.entities.origintype.md)
## entities.OriginType type
**Signature:**
```typescript
export declare type OriginType = "combined" | "local" | "remote";
```

View File

@ -1,33 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Page](./calckey-js.entities.page.md)
## entities.Page type
**Signature:**
```typescript
export declare type Page = {
id: ID;
createdAt: DateString;
updatedAt: DateString;
userId: User["id"];
user: User;
content: Record<string, any>[];
variables: Record<string, any>[];
title: string;
name: string;
summary: string | null;
hideTitleWhenPinned: boolean;
alignCenter: boolean;
font: string;
script: string;
eyeCatchingImageId: DriveFile["id"] | null;
eyeCatchingImage: DriveFile | null;
attachedFiles: any;
likedCount: number;
isLiked?: boolean;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [User](./calckey-js.entities.user.md)<!-- -->, [DriveFile](./calckey-js.entities.drivefile.md)

View File

@ -1,19 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [PageEvent](./calckey-js.entities.pageevent.md)
## entities.PageEvent type
**Signature:**
```typescript
export declare type PageEvent = {
pageId: Page["id"];
event: string;
var: any;
userId: User["id"];
user: User;
};
```
**References:** [Page](./calckey-js.entities.page.md)<!-- -->, [User](./calckey-js.entities.user.md)

View File

@ -1,24 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [ServerInfo](./calckey-js.entities.serverinfo.md)
## entities.ServerInfo type
**Signature:**
```typescript
export declare type ServerInfo = {
machine: string;
cpu: {
model: string;
cores: number;
};
mem: {
total: number;
};
fs: {
total: number;
used: number;
};
};
```

View File

@ -1,19 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Signin](./calckey-js.entities.signin.md)
## entities.Signin type
**Signature:**
```typescript
export declare type Signin = {
id: ID;
createdAt: DateString;
ip: string;
headers: Record<string, any>;
success: boolean;
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)

View File

@ -1,19 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [Stats](./calckey-js.entities.stats.md)
## entities.Stats type
**Signature:**
```typescript
export declare type Stats = {
notesCount: number;
originalNotesCount: number;
usersCount: number;
originalUsersCount: number;
instances: number;
driveUsageLocal: number;
driveUsageRemote: number;
};
```

View File

@ -1,13 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [User](./calckey-js.entities.user.md)
## entities.User type
**Signature:**
```typescript
export declare type User = UserLite | UserDetailed;
```
**References:** [UserLite](./calckey-js.entities.userlite.md)<!-- -->, [UserDetailed](./calckey-js.entities.userdetailed.md)

View File

@ -1,56 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [UserDetailed](./calckey-js.entities.userdetailed.md)
## entities.UserDetailed type
**Signature:**
```typescript
export declare type UserDetailed = UserLite & {
bannerBlurhash: string | null;
bannerColor: string | null;
bannerUrl: string | null;
birthday: string | null;
createdAt: DateString;
description: string | null;
ffVisibility: "public" | "followers" | "private";
fields: {
name: string;
value: string;
}[];
followersCount: number;
followingCount: number;
hasPendingFollowRequestFromYou: boolean;
hasPendingFollowRequestToYou: boolean;
isAdmin: boolean;
isBlocked: boolean;
isBlocking: boolean;
isBot: boolean;
isCat: boolean;
isFollowed: boolean;
isFollowing: boolean;
isLocked: boolean;
isModerator: boolean;
isMuted: boolean;
isRenoteMuted: boolean;
isSilenced: boolean;
isSuspended: boolean;
lang: string | null;
lastFetchedAt?: DateString;
location: string | null;
notesCount: number;
pinnedNoteIds: ID[];
pinnedNotes: Note[];
pinnedPage: Page | null;
pinnedPageId: string | null;
publicReactions: boolean;
securityKeys: boolean;
twoFactorEnabled: boolean;
updatedAt: DateString | null;
uri: string | null;
url: string | null;
};
```
**References:** [UserLite](./calckey-js.entities.userlite.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [ID](./calckey-js.entities.id.md)<!-- -->, [Note](./calckey-js.entities.note.md)<!-- -->, [Page](./calckey-js.entities.page.md)

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [UserGroup](./calckey-js.entities.usergroup.md)
## entities.UserGroup type
**Signature:**
```typescript
export declare type UserGroup = TODO;
```

View File

@ -1,18 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [UserList](./calckey-js.entities.userlist.md)
## entities.UserList type
**Signature:**
```typescript
export declare type UserList = {
id: ID;
createdAt: DateString;
name: string;
userIds: User["id"][];
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [DateString](./calckey-js.entities.datestring.md)<!-- -->, [User](./calckey-js.entities.user.md)

View File

@ -1,35 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [UserLite](./calckey-js.entities.userlite.md)
## entities.UserLite type
**Signature:**
```typescript
export declare type UserLite = {
id: ID;
username: string;
host: string | null;
name: string;
onlineStatus: "online" | "active" | "offline" | "unknown";
avatarUrl: string;
avatarBlurhash: string;
alsoKnownAs: string[];
movedToUri: any;
emojis: {
name: string;
url: string;
}[];
instance?: {
name: Instance["name"];
softwareName: Instance["softwareName"];
softwareVersion: Instance["softwareVersion"];
iconUrl: Instance["iconUrl"];
faviconUrl: Instance["faviconUrl"];
themeColor: Instance["themeColor"];
};
};
```
**References:** [ID](./calckey-js.entities.id.md)<!-- -->, [Instance](./calckey-js.entities.instance.md)

View File

@ -1,17 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [entities](./calckey-js.entities.md) &gt; [UserSorting](./calckey-js.entities.usersorting.md)
## entities.UserSorting type
**Signature:**
```typescript
export declare type UserSorting =
| "+follower"
| "-follower"
| "+createdAt"
| "-createdAt"
| "+updatedAt"
| "-updatedAt";
```

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [ffVisibility](./calckey-js.ffvisibility.md)
## ffVisibility variable
**Signature:**
```typescript
ffVisibility: readonly ["public", "followers", "private"]
```

View File

@ -1,43 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md)
## calckey-js package
## Classes
| Class | Description |
| --- | --- |
| [Stream](./calckey-js.stream.md) | |
## Abstract Classes
| Abstract Class | Description |
| --- | --- |
| [ChannelConnection](./calckey-js.channelconnection.md) | |
## Namespaces
| Namespace | Description |
| --- | --- |
| [api](./calckey-js.api.md) | |
| [entities](./calckey-js.entities.md) | |
## Variables
| Variable | Description |
| --- | --- |
| [ffVisibility](./calckey-js.ffvisibility.md) | |
| [mutedNoteReasons](./calckey-js.mutednotereasons.md) | |
| [noteVisibilities](./calckey-js.notevisibilities.md) | |
| [notificationTypes](./calckey-js.notificationtypes.md) | |
| [permissions](./calckey-js.permissions.md) | |
## Type Aliases
| Type Alias | Description |
| --- | --- |
| [Acct](./calckey-js.acct.md) | |
| [Channels](./calckey-js.channels.md) | |
| [Endpoints](./calckey-js.endpoints.md) | |

View File

@ -1,16 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [mutedNoteReasons](./calckey-js.mutednotereasons.md)
## mutedNoteReasons variable
**Signature:**
```typescript
mutedNoteReasons: readonly [
"word",
"manual",
"spam",
"other",
]
```

View File

@ -1,16 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [noteVisibilities](./calckey-js.notevisibilities.md)
## noteVisibilities variable
**Signature:**
```typescript
noteVisibilities: readonly [
"public",
"home",
"followers",
"specified",
]
```

View File

@ -1,24 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [notificationTypes](./calckey-js.notificationtypes.md)
## notificationTypes variable
**Signature:**
```typescript
notificationTypes: readonly [
"follow",
"mention",
"reply",
"renote",
"quote",
"reaction",
"pollVote",
"pollEnded",
"receiveFollowRequest",
"followRequestAccepted",
"groupInvited",
"app",
]
```

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [permissions](./calckey-js.permissions.md)
## permissions variable
**Signature:**
```typescript
permissions: string[]
```

View File

@ -1,30 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md) &gt; [(constructor)](./calckey-js.stream._constructor_.md)
## Stream.(constructor)
Constructs a new instance of the `Stream` class
**Signature:**
```typescript
constructor(
origin: string,
user: {
token: string;
} | null,
options?: {
WebSocket?: any;
},
);
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| origin | string | |
| user | { token: string; } \| null | |
| options | { WebSocket?: any; } | _(Optional)_ |

View File

@ -1,15 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md) &gt; [close](./calckey-js.stream.close.md)
## Stream.close() method
**Signature:**
```typescript
close(): void;
```
**Returns:**
void

View File

@ -1,22 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md) &gt; [disconnectToChannel](./calckey-js.stream.disconnecttochannel.md)
## Stream.disconnectToChannel() method
**Signature:**
```typescript
disconnectToChannel(connection: NonSharedConnection): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| connection | NonSharedConnection | |
**Returns:**
void

View File

@ -1,36 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md)
## Stream class
**Signature:**
```typescript
export default class Stream extends EventEmitter<StreamEvents>
```
**Extends:** EventEmitter&lt;StreamEvents&gt;
## Constructors
| Constructor | Modifiers | Description |
| --- | --- | --- |
| [(constructor)(origin, user, options)](./calckey-js.stream._constructor_.md) | | Constructs a new instance of the <code>Stream</code> class |
## Properties
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [state](./calckey-js.stream.state.md) | | "initializing" \| "reconnecting" \| "connected" | |
## Methods
| Method | Modifiers | Description |
| --- | --- | --- |
| [close()](./calckey-js.stream.close.md) | | |
| [disconnectToChannel(connection)](./calckey-js.stream.disconnecttochannel.md) | | |
| [removeSharedConnection(connection)](./calckey-js.stream.removesharedconnection.md) | | |
| [removeSharedConnectionPool(pool)](./calckey-js.stream.removesharedconnectionpool.md) | | |
| [send(typeOrPayload, payload)](./calckey-js.stream.send.md) | | |
| [useChannel(channel, params, name)](./calckey-js.stream.usechannel.md) | | |

View File

@ -1,22 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md) &gt; [removeSharedConnection](./calckey-js.stream.removesharedconnection.md)
## Stream.removeSharedConnection() method
**Signature:**
```typescript
removeSharedConnection(connection: SharedConnection): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| connection | SharedConnection | |
**Returns:**
void

View File

@ -1,22 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md) &gt; [removeSharedConnectionPool](./calckey-js.stream.removesharedconnectionpool.md)
## Stream.removeSharedConnectionPool() method
**Signature:**
```typescript
removeSharedConnectionPool(pool: Pool): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| pool | Pool | |
**Returns:**
void

View File

@ -1,23 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md) &gt; [send](./calckey-js.stream.send.md)
## Stream.send() method
**Signature:**
```typescript
send(typeOrPayload: any, payload?: any): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| typeOrPayload | any | |
| payload | any | _(Optional)_ |
**Returns:**
void

View File

@ -1,11 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md) &gt; [state](./calckey-js.stream.state.md)
## Stream.state property
**Signature:**
```typescript
state: "initializing" | "reconnecting" | "connected";
```

View File

@ -1,28 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [calckey-js](./calckey-js.md) &gt; [Stream](./calckey-js.stream.md) &gt; [useChannel](./calckey-js.stream.usechannel.md)
## Stream.useChannel() method
**Signature:**
```typescript
useChannel<C extends keyof Channels>(
channel: C,
params?: Channels[C]["params"],
name?: string,
): Connection<Channels[C]>;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
| channel | C | |
| params | [Channels](./calckey-js.channels.md)<!-- -->\[C\]\["params"\] | _(Optional)_ |
| name | string | _(Optional)_ |
**Returns:**
[Connection](./calckey-js.channelconnection.md)<!-- -->&lt;[Channels](./calckey-js.channels.md)<!-- -->\[C\]&gt;

View File

@ -1,12 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md)
## API Reference
## Packages
| Package | Description |
| --- | --- |
| [calckey-js](./calckey-js.md) | |

View File

@ -6,19 +6,13 @@
"types": "./built/index.d.ts", "types": "./built/index.d.ts",
"scripts": { "scripts": {
"build": "pnpm swc src -d built -D", "build": "pnpm swc src -d built -D",
"render": "pnpm run build && pnpm run api && pnpm run api-prod && cp temp/calckey-js.api.json etc/ && pnpm run api-doc", "tsd": "tsc && tsd"
"tsd": "tsc && tsd",
"api": "pnpm api-extractor run --local --verbose",
"api-prod": "pnpm api-extractor run --verbose",
"api-doc": "pnpm api-documenter markdown -i ./etc/"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://codeberg.org/calckey/calckey.git" "url": "https://codeberg.org/calckey/calckey.git"
}, },
"devDependencies": { "devDependencies": {
"@microsoft/api-extractor": "^7.36.0",
"@microsoft/api-documenter": "^7.22.21",
"@swc/cli": "^0.1.62", "@swc/cli": "^0.1.62",
"@swc/core": "^1.3.62", "@swc/core": "^1.3.62",
"@types/node": "20.3.1", "@types/node": "20.3.1",

View File

@ -97,7 +97,6 @@ export type MeDetailed = UserDetailed & {
hasUnreadSpecifiedNotes: boolean; hasUnreadSpecifiedNotes: boolean;
hideOnlineStatus: boolean; hideOnlineStatus: boolean;
injectFeaturedNote: boolean; injectFeaturedNote: boolean;
integrations: Record<string, any>;
isDeleted: boolean; isDeleted: boolean;
isExplorable: boolean; isExplorable: boolean;
mutedWords: string[][]; mutedWords: string[][];
@ -290,9 +289,6 @@ export type LiteInstanceMetadata = {
swPublickey: string | null; swPublickey: string | null;
maxNoteTextLength: number; maxNoteTextLength: number;
enableEmail: boolean; enableEmail: boolean;
enableTwitterIntegration: boolean;
enableGithubIntegration: boolean;
enableDiscordIntegration: boolean;
enableServiceWorker: boolean; enableServiceWorker: boolean;
emojis: CustomEmoji[]; emojis: CustomEmoji[];
ads: { ads: {

View File

@ -14,281 +14,291 @@ const accountData = localStorage.getItem("account");
// TODO: 外部からはreadonlyに // TODO: 外部からはreadonlyに
export const $i = accountData export const $i = accountData
? reactive(JSON.parse(accountData) as Account) ? reactive(JSON.parse(accountData) as Account)
: null; : null;
export const iAmModerator = $i != null && ($i.isAdmin || $i.isModerator); export const iAmModerator = $i != null && ($i.isAdmin || $i.isModerator);
export const iAmAdmin = $i?.isAdmin; export const iAmAdmin = $i?.isAdmin;
export async function signout() { export async function signout() {
waiting(); waiting();
localStorage.removeItem("account"); localStorage.removeItem("account");
await removeAccount($i.id); await removeAccount($i.id);
const accounts = await getAccounts(); const accounts = await getAccounts();
//#region Remove service worker registration //#region Remove service worker registration
try { try {
if (navigator.serviceWorker.controller) { if (navigator.serviceWorker.controller) {
const registration = await navigator.serviceWorker.ready; const registration = await navigator.serviceWorker.ready;
const push = await registration.pushManager.getSubscription(); const push = await registration.pushManager.getSubscription();
if (push) { if (push) {
await fetch(`${apiUrl}/sw/unregister`, { await fetch(`${apiUrl}/sw/unregister`, {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
i: $i.token, i: $i.token,
endpoint: push.endpoint, endpoint: push.endpoint,
}), }),
}); });
} }
} }
if (accounts.length === 0) { if (accounts.length === 0) {
await navigator.serviceWorker.getRegistrations().then((registrations) => { await navigator.serviceWorker
return Promise.all( .getRegistrations()
registrations.map((registration) => registration.unregister()), .then((registrations) => {
); return Promise.all(
}); registrations.map((registration) =>
} registration.unregister()
} catch (err) {} )
//#endregion );
});
}
} catch (err) {}
//#endregion
document.cookie = "igi=; path=/"; document.cookie = "igi=; path=/";
if (accounts.length > 0) login(accounts[0].token); if (accounts.length > 0) login(accounts[0].token);
else unisonReload("/"); else unisonReload("/");
} }
export async function getAccounts(): Promise< export async function getAccounts(): Promise<
{ id: Account["id"]; token: Account["token"] }[] { id: Account["id"]; token: Account["token"] }[]
> { > {
return (await get("accounts")) || []; return (await get("accounts")) || [];
} }
export async function addAccount(id: Account["id"], token: Account["token"]) { export async function addAccount(id: Account["id"], token: Account["token"]) {
const accounts = await getAccounts(); const accounts = await getAccounts();
if (!accounts.some((x) => x.id === id)) { if (!accounts.some((x) => x.id === id)) {
await set("accounts", accounts.concat([{ id, token }])); await set("accounts", accounts.concat([{ id, token }]));
} }
} }
export async function removeAccount(id: Account["id"]) { export async function removeAccount(id: Account["id"]) {
const accounts = await getAccounts(); const accounts = await getAccounts();
accounts.splice( accounts.splice(
accounts.findIndex((x) => x.id === id), accounts.findIndex((x) => x.id === id),
1, 1
); );
if (accounts.length > 0) await set("accounts", accounts); if (accounts.length > 0) await set("accounts", accounts);
else await del("accounts"); else await del("accounts");
} }
function fetchAccount(token: string): Promise<Account> { function fetchAccount(token: string): Promise<Account> {
return new Promise((done, fail) => { return new Promise((done, fail) => {
// Fetch user // Fetch user
fetch(`${apiUrl}/i`, { fetch(`${apiUrl}/i`, {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
i: token, i: token,
}), }),
}) })
.then((res) => res.json()) .then((res) => res.json())
.then((res) => { .then((res) => {
if (res.error) { if (res.error) {
if (res.error.id === "a8c724b3-6e9c-4b46-b1a8-bc3ed6258370") { if (
showSuspendedDialog().then(() => { res.error.id === "a8c724b3-6e9c-4b46-b1a8-bc3ed6258370"
signout(); ) {
}); showSuspendedDialog().then(() => {
} else { signout();
alert({ });
type: "error", } else {
title: i18n.ts.failedToFetchAccountInformation, alert({
text: JSON.stringify(res.error), type: "error",
}); title: i18n.ts.failedToFetchAccountInformation,
} text: JSON.stringify(res.error),
} else { });
res.token = token; }
done(res); } else {
} res.token = token;
}) done(res);
.catch(fail); }
}); })
.catch(fail);
});
} }
export function updateAccount(accountData) { export function updateAccount(accountData) {
for (const [key, value] of Object.entries(accountData)) { for (const [key, value] of Object.entries(accountData)) {
$i[key] = value; $i[key] = value;
} }
localStorage.setItem("account", JSON.stringify($i)); localStorage.setItem("account", JSON.stringify($i));
} }
export function refreshAccount() { export function refreshAccount() {
return fetchAccount($i.token).then(updateAccount); return fetchAccount($i.token).then(updateAccount);
} }
export async function login(token: Account["token"], redirect?: string) { export async function login(token: Account["token"], redirect?: string) {
waiting(); waiting();
if (_DEV_) console.log("logging as token ", token); if (_DEV_) console.log("logging as token ", token);
const me = await fetchAccount(token); const me = await fetchAccount(token);
localStorage.setItem("account", JSON.stringify(me)); localStorage.setItem("account", JSON.stringify(me));
document.cookie = `token=${token}; path=/; max-age=31536000`; // bull dashboardの認証とかで使う document.cookie = `token=${token}; path=/; max-age=31536000`; // bull dashboardの認証とかで使う
await addAccount(me.id, token); await addAccount(me.id, token);
if (redirect) { if (redirect) {
// 他のタブは再読み込みするだけ // 他のタブは再読み込みするだけ
reloadChannel.postMessage(null); reloadChannel.postMessage(null);
// このページはredirectで指定された先に移動 // このページはredirectで指定された先に移動
location.href = redirect; location.href = redirect;
return; return;
} }
unisonReload(); unisonReload();
} }
export async function openAccountMenu( export async function openAccountMenu(
opts: { opts: {
includeCurrentAccount?: boolean; includeCurrentAccount?: boolean;
withExtraOperation: boolean; withExtraOperation: boolean;
active?: misskey.entities.UserDetailed["id"]; active?: misskey.entities.UserDetailed["id"];
onChoose?: (account: misskey.entities.UserDetailed) => void; onChoose?: (account: misskey.entities.UserDetailed) => void;
}, },
ev: MouseEvent, ev: MouseEvent
) { ) {
function showSigninDialog() { function showSigninDialog() {
popup( popup(
defineAsyncComponent(() => import("@/components/MkSigninDialog.vue")), defineAsyncComponent(
{}, () => import("@/components/MkSigninDialog.vue")
{ ),
done: (res) => { {},
addAccount(res.id, res.i); {
success(); done: (res) => {
}, addAccount(res.id, res.i);
}, success();
"closed", },
); },
} "closed"
);
}
function createAccount() { function createAccount() {
popup( popup(
defineAsyncComponent(() => import("@/components/MkSignupDialog.vue")), defineAsyncComponent(
{}, () => import("@/components/MkSignupDialog.vue")
{ ),
done: (res) => { {},
addAccount(res.id, res.i); {
switchAccountWithToken(res.i); done: (res) => {
}, addAccount(res.id, res.i);
}, switchAccountWithToken(res.i);
"closed", },
); },
} "closed"
);
}
async function switchAccount(account: misskey.entities.UserDetailed) { async function switchAccount(account: misskey.entities.UserDetailed) {
const storedAccounts = await getAccounts(); const storedAccounts = await getAccounts();
const token = storedAccounts.find((x) => x.id === account.id).token; const token = storedAccounts.find((x) => x.id === account.id).token;
switchAccountWithToken(token); switchAccountWithToken(token);
} }
function switchAccountWithToken(token: string) { function switchAccountWithToken(token: string) {
login(token); login(token);
} }
const storedAccounts = await getAccounts().then((accounts) => const storedAccounts = await getAccounts().then((accounts) =>
accounts.filter((x) => x.id !== $i.id), accounts.filter((x) => x.id !== $i.id)
); );
const accountsPromise = api("users/show", { const accountsPromise = api("users/show", {
userIds: storedAccounts.map((x) => x.id), userIds: storedAccounts.map((x) => x.id),
}); });
function createItem(account: misskey.entities.UserDetailed) { function createItem(account: misskey.entities.UserDetailed) {
return { return {
type: "user", type: "user",
user: account, user: account,
active: opts.active != null ? opts.active === account.id : false, active: opts.active != null ? opts.active === account.id : false,
action: () => { action: () => {
if (opts.onChoose) { if (opts.onChoose) {
opts.onChoose(account); opts.onChoose(account);
} else { } else {
switchAccount(account); switchAccount(account);
} }
}, },
}; };
} }
const accountItemPromises = storedAccounts.map( const accountItemPromises = storedAccounts.map(
(a) => (a) =>
new Promise((res) => { new Promise((res) => {
accountsPromise.then((accounts) => { accountsPromise.then((accounts) => {
const account = accounts.find((x) => x.id === a.id); const account = accounts.find((x) => x.id === a.id);
if (account == null) return res(null); if (account == null) return res(null);
res(createItem(account)); res(createItem(account));
}); });
}), })
); );
if (opts.withExtraOperation) { if (opts.withExtraOperation) {
popupMenu( popupMenu(
[ [
...[ ...[
{ {
type: "link", type: "link",
text: i18n.ts.profile, text: i18n.ts.profile,
to: `/@${$i.username}`, to: `/@${$i.username}`,
avatar: $i, avatar: $i,
}, },
null, null,
...(opts.includeCurrentAccount ? [createItem($i)] : []), ...(opts.includeCurrentAccount ? [createItem($i)] : []),
...accountItemPromises, ...accountItemPromises,
{ {
type: "parent", type: "parent",
icon: "ph-plus ph-bold ph-lg", icon: "ph-plus ph-bold ph-lg",
text: i18n.ts.addAccount, text: i18n.ts.addAccount,
children: [ children: [
{ {
text: i18n.ts.existingAccount, text: i18n.ts.existingAccount,
action: () => { action: () => {
showSigninDialog(); showSigninDialog();
}, },
}, },
{ {
text: i18n.ts.createAccount, text: i18n.ts.createAccount,
action: () => { action: () => {
createAccount(); createAccount();
}, },
}, },
], ],
}, },
{ {
type: "link", type: "link",
icon: "ph-users ph-bold ph-lg", icon: "ph-users ph-bold ph-lg",
text: i18n.ts.manageAccounts, text: i18n.ts.manageAccounts,
to: "/settings/accounts", to: "/settings/accounts",
}, },
{ {
type: "button", type: "button",
icon: "ph-sign-out ph-bold ph-lg", icon: "ph-sign-out ph-bold ph-lg",
text: i18n.ts.logout, text: i18n.ts.logout,
action: () => { action: () => {
signout(); signout();
}, },
}, },
], ],
], ],
ev.currentTarget ?? ev.target, ev.currentTarget ?? ev.target,
{ {
align: "left", align: "left",
}, }
); );
} else { } else {
popupMenu( popupMenu(
[ [
...(opts.includeCurrentAccount ? [createItem($i)] : []), ...(opts.includeCurrentAccount ? [createItem($i)] : []),
...accountItemPromises, ...accountItemPromises,
], ],
ev.currentTarget ?? ev.target, ev.currentTarget ?? ev.target,
{ {
align: "left", align: "left",
}, }
); );
} }
} }

View File

@ -1,67 +1,67 @@
<template> <template>
<div class="bcekxzvu _gap _panel"> <div class="bcekxzvu _gap _panel">
<div class="target"> <div class="target">
<MkA <MkA
v-user-preview="report.targetUserId" v-user-preview="report.targetUserId"
class="info" class="info"
:to="`/user-info/${report.targetUserId}`" :to="`/user-info/${report.targetUserId}`"
> >
<MkAvatar <MkAvatar
class="avatar" class="avatar"
:user="report.targetUser" :user="report.targetUser"
:show-indicator="true" :show-indicator="true"
:disable-link="true" :disable-link="true"
/> />
<div class="names"> <div class="names">
<MkUserName class="name" :user="report.targetUser" /> <MkUserName class="name" :user="report.targetUser" />
<MkAcct <MkAcct
class="acct" class="acct"
:user="report.targetUser" :user="report.targetUser"
style="display: block" style="display: block"
/> />
</div> </div>
</MkA> </MkA>
<MkKeyValue class="_formBlock"> <MkKeyValue class="_formBlock">
<template #key>{{ i18n.ts.registeredDate }}</template> <template #key>{{ i18n.ts.registeredDate }}</template>
<template #value <template #value
>{{ >{{
new Date(report.targetUser.createdAt).toLocaleString() new Date(report.targetUser.createdAt).toLocaleString()
}} }}
(<MkTime :time="report.targetUser.createdAt" />)</template (<MkTime :time="report.targetUser.createdAt" />)</template
> >
</MkKeyValue> </MkKeyValue>
</div> </div>
<div class="detail"> <div class="detail">
<div> <div>
<Mfm :text="report.comment" /> <Mfm :text="report.comment" />
</div> </div>
<hr /> <hr />
<div> <div>
{{ i18n.ts.reporter }}: <MkAcct :user="report.reporter" /> {{ i18n.ts.reporter }}: <MkAcct :user="report.reporter" />
</div> </div>
<div v-if="report.assignee"> <div v-if="report.assignee">
{{ i18n.ts.moderator }}: {{ i18n.ts.moderator }}:
<MkAcct :user="report.assignee" /> <MkAcct :user="report.assignee" />
</div> </div>
<div><MkTime :time="report.createdAt" /></div> <div><MkTime :time="report.createdAt" /></div>
<div class="action"> <div class="action">
<MkSwitch <MkSwitch
v-model="forward" v-model="forward"
:disabled=" :disabled="
report.targetUser.host == null || report.resolved report.targetUser.host == null || report.resolved
" "
> >
{{ i18n.ts.forwardReport }} {{ i18n.ts.forwardReport }}
<template #caption>{{ <template #caption>{{
i18n.ts.forwardReportIsAnonymous i18n.ts.forwardReportIsAnonymous
}}</template> }}</template>
</MkSwitch> </MkSwitch>
<MkButton v-if="!report.resolved" primary @click="resolve">{{ <MkButton v-if="!report.resolved" primary @click="resolve">{{
i18n.ts.abuseMarkAsResolved i18n.ts.abuseMarkAsResolved
}}</MkButton> }}</MkButton>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -73,75 +73,75 @@ import * as os from "@/os";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const props = defineProps<{ const props = defineProps<{
report: any; report: any;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "resolved", reportId: string): void; (ev: "resolved", reportId: string): void;
}>(); }>();
let forward = $ref(props.report.forwarded); let forward = $ref(props.report.forwarded);
function resolve() { function resolve() {
os.apiWithDialog("admin/resolve-abuse-user-report", { os.apiWithDialog("admin/resolve-abuse-user-report", {
forward: forward, forward: forward,
reportId: props.report.id, reportId: props.report.id,
}).then(() => { }).then(() => {
emit("resolved", props.report.id); emit("resolved", props.report.id);
}); });
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.bcekxzvu { .bcekxzvu {
display: flex; display: flex;
> .target { > .target {
width: 35%; width: 35%;
box-sizing: border-box; box-sizing: border-box;
text-align: left; text-align: left;
padding: 24px; padding: 24px;
border-right: solid 1px var(--divider); border-right: solid 1px var(--divider);
> .info { > .info {
display: flex; display: flex;
box-sizing: border-box; box-sizing: border-box;
align-items: center; align-items: center;
padding: 14px; padding: 14px;
border-radius: 8px; border-radius: 8px;
--c: rgb(255 196 0 / 15%); --c: rgb(255 196 0 / 15%);
background-image: linear-gradient( background-image: linear-gradient(
45deg, 45deg,
var(--c) 16.67%, var(--c) 16.67%,
transparent 16.67%, transparent 16.67%,
transparent 50%, transparent 50%,
var(--c) 50%, var(--c) 50%,
var(--c) 66.67%, var(--c) 66.67%,
transparent 66.67%, transparent 66.67%,
transparent 100% transparent 100%
); );
background-size: 16px 16px; background-size: 16px 16px;
> .avatar { > .avatar {
width: 42px; width: 42px;
height: 42px; height: 42px;
} }
> .names { > .names {
margin-left: 0.3em; margin-left: 0.3em;
padding: 0 8px; padding: 0 8px;
flex: 1; flex: 1;
> .name { > .name {
font-weight: bold; font-weight: bold;
} }
} }
} }
} }
> .detail { > .detail {
flex: 1; flex: 1;
padding: 24px; padding: 24px;
} }
} }
</style> </style>

View File

@ -1,42 +1,42 @@
<template> <template>
<XWindow <XWindow
ref="uiWindow" ref="uiWindow"
:initial-width="400" :initial-width="400"
:initial-height="500" :initial-height="500"
:can-resize="true" :can-resize="true"
@closed="emit('closed')" @closed="emit('closed')"
> >
<template #header> <template #header>
<i <i
class="ph-warning-circle ph-bold ph-lg" class="ph-warning-circle ph-bold ph-lg"
style="margin-right: 0.5em" style="margin-right: 0.5em"
></i> ></i>
<I18n :src="i18n.ts.reportAbuseOf" tag="span"> <I18n :src="i18n.ts.reportAbuseOf" tag="span">
<template #name> <template #name>
<b><MkAcct :user="user" /></b> <b><MkAcct :user="user" /></b>
</template> </template>
</I18n> </I18n>
</template> </template>
<div class="dpvffvvy _monolithic_"> <div class="dpvffvvy _monolithic_">
<div class="_section"> <div class="_section">
<MkTextarea v-model="comment"> <MkTextarea v-model="comment">
<template #label>{{ i18n.ts.details }}</template> <template #label>{{ i18n.ts.details }}</template>
<template #caption>{{ <template #caption>{{
i18n.ts.fillAbuseReportDescription i18n.ts.fillAbuseReportDescription
}}</template> }}</template>
</MkTextarea> </MkTextarea>
</div> </div>
<div class="_section"> <div class="_section">
<MkButton <MkButton
primary primary
full full
:disabled="comment.length === 0" :disabled="comment.length === 0"
@click="send" @click="send"
>{{ i18n.ts.send }}</MkButton >{{ i18n.ts.send }}</MkButton
> >
</div> </div>
</div> </div>
</XWindow> </XWindow>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -49,38 +49,38 @@ import * as os from "@/os";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const props = defineProps<{ const props = defineProps<{
user: Misskey.entities.User; user: Misskey.entities.User;
initialComment?: string; initialComment?: string;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "closed"): void; (ev: "closed"): void;
}>(); }>();
const uiWindow = ref<InstanceType<typeof XWindow>>(); const uiWindow = ref<InstanceType<typeof XWindow>>();
const comment = ref(props.initialComment || ""); const comment = ref(props.initialComment || "");
function send() { function send() {
os.apiWithDialog( os.apiWithDialog(
"users/report-abuse", "users/report-abuse",
{ {
userId: props.user.id, userId: props.user.id,
comment: comment.value, comment: comment.value,
}, },
undefined undefined
).then((res) => { ).then((res) => {
os.alert({ os.alert({
type: "success", type: "success",
text: i18n.ts.abuseReported, text: i18n.ts.abuseReported,
}); });
uiWindow.value?.close(); uiWindow.value?.close();
emit("closed"); emit("closed");
}); });
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.dpvffvvy { .dpvffvvy {
--root-margin: 16px; --root-margin: 16px;
} }
</style> </style>

View File

@ -1,62 +1,62 @@
<template> <template>
<svg class="mbcofsoe" viewBox="0 0 10 10" preserveAspectRatio="none"> <svg class="mbcofsoe" viewBox="0 0 10 10" preserveAspectRatio="none">
<template v-if="props.graduations === 'dots'"> <template v-if="props.graduations === 'dots'">
<circle <circle
v-for="(angle, i) in graduationsMajor" v-for="(angle, i) in graduationsMajor"
:cx="5 + Math.sin(angle) * (5 - graduationsPadding)" :cx="5 + Math.sin(angle) * (5 - graduationsPadding)"
:cy="5 - Math.cos(angle) * (5 - graduationsPadding)" :cy="5 - Math.cos(angle) * (5 - graduationsPadding)"
:r="0.125" :r="0.125"
:fill=" :fill="
(props.twentyfour ? h : h % 12) === i (props.twentyfour ? h : h % 12) === i
? nowColor ? nowColor
: majorGraduationColor : majorGraduationColor
" "
:opacity=" :opacity="
!props.fadeGraduations || !props.fadeGraduations ||
(props.twentyfour ? h : h % 12) === i (props.twentyfour ? h : h % 12) === i
? 1 ? 1
: Math.max( : Math.max(
0, 0,
1 - 1 -
angleDiff(hAngle, angle) / Math.PI - angleDiff(hAngle, angle) / Math.PI -
numbersOpacityFactor numbersOpacityFactor
) )
" "
/> />
</template> </template>
<template v-else-if="props.graduations === 'numbers'"> <template v-else-if="props.graduations === 'numbers'">
<text <text
v-for="(angle, i) in texts" v-for="(angle, i) in texts"
:x="5 + Math.sin(angle) * (5 - textsPadding)" :x="5 + Math.sin(angle) * (5 - textsPadding)"
:y="5 - Math.cos(angle) * (5 - textsPadding)" :y="5 - Math.cos(angle) * (5 - textsPadding)"
text-anchor="middle" text-anchor="middle"
dominant-baseline="middle" dominant-baseline="middle"
:font-size="(props.twentyfour ? h : h % 12) === i ? 1 : 0.7" :font-size="(props.twentyfour ? h : h % 12) === i ? 1 : 0.7"
:font-weight=" :font-weight="
(props.twentyfour ? h : h % 12) === i ? 'bold' : 'normal' (props.twentyfour ? h : h % 12) === i ? 'bold' : 'normal'
" "
:fill=" :fill="
(props.twentyfour ? h : h % 12) === i (props.twentyfour ? h : h % 12) === i
? nowColor ? nowColor
: 'currentColor' : 'currentColor'
" "
:opacity=" :opacity="
!props.fadeGraduations || !props.fadeGraduations ||
(props.twentyfour ? h : h % 12) === i (props.twentyfour ? h : h % 12) === i
? 1 ? 1
: Math.max( : Math.max(
0, 0,
1 - 1 -
angleDiff(hAngle, angle) / Math.PI - angleDiff(hAngle, angle) / Math.PI -
numbersOpacityFactor numbersOpacityFactor
) )
" "
> >
{{ i === 0 ? (props.twentyfour ? "24" : "12") : i }} {{ i === 0 ? (props.twentyfour ? "24" : "12") : i }}
</text> </text>
</template> </template>
<!-- <!--
<line <line
:x1="5 - (Math.sin(sAngle) * (sHandLengthRatio * handsTailLength))" :x1="5 - (Math.sin(sAngle) * (sHandLengthRatio * handsTailLength))"
:y1="5 + (Math.cos(sAngle) * (sHandLengthRatio * handsTailLength))" :y1="5 + (Math.cos(sAngle) * (sHandLengthRatio * handsTailLength))"
@ -68,61 +68,61 @@
/> />
--> -->
<line <line
class="s" class="s"
:class="{ :class="{
animate: !disableSAnimate && sAnimation !== 'none', animate: !disableSAnimate && sAnimation !== 'none',
elastic: sAnimation === 'elastic', elastic: sAnimation === 'elastic',
easeOut: sAnimation === 'easeOut', easeOut: sAnimation === 'easeOut',
}" }"
:x1="5 - 0 * (sHandLengthRatio * handsTailLength)" :x1="5 - 0 * (sHandLengthRatio * handsTailLength)"
:y1="5 + 1 * (sHandLengthRatio * handsTailLength)" :y1="5 + 1 * (sHandLengthRatio * handsTailLength)"
:x2="5 + 0 * (sHandLengthRatio * 5 - handsPadding)" :x2="5 + 0 * (sHandLengthRatio * 5 - handsPadding)"
:y2="5 - 1 * (sHandLengthRatio * 5 - handsPadding)" :y2="5 - 1 * (sHandLengthRatio * 5 - handsPadding)"
:stroke="sHandColor" :stroke="sHandColor"
:stroke-width="thickness / 2" :stroke-width="thickness / 2"
:style="`transform: rotateZ(${sAngle}rad)`" :style="`transform: rotateZ(${sAngle}rad)`"
stroke-linecap="round" stroke-linecap="round"
/> />
<line <line
:x1="5 - Math.sin(mAngle) * (mHandLengthRatio * handsTailLength)" :x1="5 - Math.sin(mAngle) * (mHandLengthRatio * handsTailLength)"
:y1="5 + Math.cos(mAngle) * (mHandLengthRatio * handsTailLength)" :y1="5 + Math.cos(mAngle) * (mHandLengthRatio * handsTailLength)"
:x2="5 + Math.sin(mAngle) * (mHandLengthRatio * 5 - handsPadding)" :x2="5 + Math.sin(mAngle) * (mHandLengthRatio * 5 - handsPadding)"
:y2="5 - Math.cos(mAngle) * (mHandLengthRatio * 5 - handsPadding)" :y2="5 - Math.cos(mAngle) * (mHandLengthRatio * 5 - handsPadding)"
:stroke="mHandColor" :stroke="mHandColor"
:stroke-width="thickness" :stroke-width="thickness"
stroke-linecap="round" stroke-linecap="round"
/> />
<line <line
:x1="5 - Math.sin(hAngle) * (hHandLengthRatio * handsTailLength)" :x1="5 - Math.sin(hAngle) * (hHandLengthRatio * handsTailLength)"
:y1="5 + Math.cos(hAngle) * (hHandLengthRatio * handsTailLength)" :y1="5 + Math.cos(hAngle) * (hHandLengthRatio * handsTailLength)"
:x2="5 + Math.sin(hAngle) * (hHandLengthRatio * 5 - handsPadding)" :x2="5 + Math.sin(hAngle) * (hHandLengthRatio * 5 - handsPadding)"
:y2="5 - Math.cos(hAngle) * (hHandLengthRatio * 5 - handsPadding)" :y2="5 - Math.cos(hAngle) * (hHandLengthRatio * 5 - handsPadding)"
:stroke="hHandColor" :stroke="hHandColor"
:stroke-width="thickness" :stroke-width="thickness"
stroke-linecap="round" stroke-linecap="round"
/> />
</svg> </svg>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { import {
ref, ref,
computed, computed,
onMounted, onMounted,
onBeforeUnmount, onBeforeUnmount,
shallowRef, shallowRef,
nextTick, nextTick,
} from "vue"; } from "vue";
import tinycolor from "tinycolor2"; import tinycolor from "tinycolor2";
import { globalEvents } from "@/events.js"; import { globalEvents } from "@/events.js";
// https://stackoverflow.com/questions/1878907/how-can-i-find-the-difference-between-two-angles // https://stackoverflow.com/questions/1878907/how-can-i-find-the-difference-between-two-angles
const angleDiff = (a: number, b: number) => { const angleDiff = (a: number, b: number) => {
const x = Math.abs(a - b); const x = Math.abs(a - b);
return Math.abs(((x + Math.PI) % (Math.PI * 2)) - Math.PI); return Math.abs(((x + Math.PI) % (Math.PI * 2)) - Math.PI);
}; };
const graduationsPadding = 0.5; const graduationsPadding = 0.5;
@ -135,42 +135,42 @@ const sHandLengthRatio = 1;
const numbersOpacityFactor = 0.35; const numbersOpacityFactor = 0.35;
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
thickness?: number; thickness?: number;
offset?: number; offset?: number;
twentyfour?: boolean; twentyfour?: boolean;
graduations?: "none" | "dots" | "numbers"; graduations?: "none" | "dots" | "numbers";
fadeGraduations?: boolean; fadeGraduations?: boolean;
sAnimation?: "none" | "elastic" | "easeOut"; sAnimation?: "none" | "elastic" | "easeOut";
}>(), }>(),
{ {
numbers: false, numbers: false,
thickness: 0.1, thickness: 0.1,
offset: 0 - new Date().getTimezoneOffset(), offset: 0 - new Date().getTimezoneOffset(),
twentyfour: false, twentyfour: false,
graduations: "dots", graduations: "dots",
fadeGraduations: true, fadeGraduations: true,
sAnimation: "elastic", sAnimation: "elastic",
} }
); );
const graduationsMajor = computed(() => { const graduationsMajor = computed(() => {
const angles: number[] = []; const angles: number[] = [];
const times = props.twentyfour ? 24 : 12; const times = props.twentyfour ? 24 : 12;
for (let i = 0; i < times; i++) { for (let i = 0; i < times; i++) {
const angle = (Math.PI * i) / (times / 2); const angle = (Math.PI * i) / (times / 2);
angles.push(angle); angles.push(angle);
} }
return angles; return angles;
}); });
const texts = computed(() => { const texts = computed(() => {
const angles: number[] = []; const angles: number[] = [];
const times = props.twentyfour ? 24 : 12; const times = props.twentyfour ? 24 : 12;
for (let i = 0; i < times; i++) { for (let i = 0; i < times; i++) {
const angle = (Math.PI * i) / (times / 2); const angle = (Math.PI * i) / (times / 2);
angles.push(angle); angles.push(angle);
} }
return angles; return angles;
}); });
let enabled = true; let enabled = true;
@ -190,91 +190,91 @@ let disableSAnimate = $ref(false);
let sOneRound = false; let sOneRound = false;
function tick() { function tick() {
const now = new Date(); const now = new Date();
now.setMinutes( now.setMinutes(
now.getMinutes() + (new Date().getTimezoneOffset() + props.offset) now.getMinutes() + (new Date().getTimezoneOffset() + props.offset)
); );
s = now.getSeconds(); s = now.getSeconds();
m = now.getMinutes(); m = now.getMinutes();
h = now.getHours(); h = now.getHours();
hAngle = hAngle =
(Math.PI * ((h % (props.twentyfour ? 24 : 12)) + (m + s / 60) / 60)) / (Math.PI * ((h % (props.twentyfour ? 24 : 12)) + (m + s / 60) / 60)) /
(props.twentyfour ? 12 : 6); (props.twentyfour ? 12 : 6);
mAngle = (Math.PI * (m + s / 60)) / 30; mAngle = (Math.PI * (m + s / 60)) / 30;
if (sOneRound) { if (sOneRound) {
// (59->0) // (59->0)
sAngle = (Math.PI * 60) / 30; sAngle = (Math.PI * 60) / 30;
window.setTimeout(() => { window.setTimeout(() => {
disableSAnimate = true; disableSAnimate = true;
window.setTimeout(() => { window.setTimeout(() => {
sAngle = 0; sAngle = 0;
window.setTimeout(() => { window.setTimeout(() => {
disableSAnimate = false; disableSAnimate = false;
}, 100); }, 100);
}, 100); }, 100);
}, 700); }, 700);
} else { } else {
sAngle = (Math.PI * s) / 30; sAngle = (Math.PI * s) / 30;
} }
sOneRound = s === 59; sOneRound = s === 59;
} }
tick(); tick();
function calcColors() { function calcColors() {
const computedStyle = getComputedStyle(document.documentElement); const computedStyle = getComputedStyle(document.documentElement);
const dark = tinycolor(computedStyle.getPropertyValue("--bg")).isDark(); const dark = tinycolor(computedStyle.getPropertyValue("--bg")).isDark();
const accent = tinycolor( const accent = tinycolor(
computedStyle.getPropertyValue("--accent") computedStyle.getPropertyValue("--accent")
).toHexString(); ).toHexString();
majorGraduationColor = dark majorGraduationColor = dark
? "rgba(255, 255, 255, 0.3)" ? "rgba(255, 255, 255, 0.3)"
: "rgba(0, 0, 0, 0.3)"; : "rgba(0, 0, 0, 0.3)";
//minorGraduationColor = dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; //minorGraduationColor = dark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
sHandColor = dark ? "rgba(255, 255, 255, 0.5)" : "rgba(0, 0, 0, 0.3)"; sHandColor = dark ? "rgba(255, 255, 255, 0.5)" : "rgba(0, 0, 0, 0.3)";
mHandColor = tinycolor( mHandColor = tinycolor(
computedStyle.getPropertyValue("--fg") computedStyle.getPropertyValue("--fg")
).toHexString(); ).toHexString();
hHandColor = accent; hHandColor = accent;
nowColor = accent; nowColor = accent;
} }
calcColors(); calcColors();
onMounted(() => { onMounted(() => {
const update = () => { const update = () => {
if (enabled) { if (enabled) {
tick(); tick();
window.setTimeout(update, 1000); window.setTimeout(update, 1000);
} }
}; };
update(); update();
globalEvents.on("themeChanged", calcColors); globalEvents.on("themeChanged", calcColors);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
enabled = false; enabled = false;
globalEvents.off("themeChanged", calcColors); globalEvents.off("themeChanged", calcColors);
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.mbcofsoe { .mbcofsoe {
display: block; display: block;
> .s { > .s {
will-change: transform; will-change: transform;
transform-origin: 50% 50%; transform-origin: 50% 50%;
&.animate.elastic { &.animate.elastic {
transition: transform 0.2s cubic-bezier(0.4, 2.08, 0.55, 0.44); transition: transform 0.2s cubic-bezier(0.4, 2.08, 0.55, 0.44);
} }
&.animate.easeOut { &.animate.easeOut {
transition: transform 0.7s cubic-bezier(0, 0.7, 0.3, 1); transition: transform 0.7s cubic-bezier(0, 0.7, 0.3, 1);
} }
} }
} }
</style> </style>

View File

@ -1,96 +1,96 @@
<template> <template>
<div <div
ref="rootEl" ref="rootEl"
class="swhvrteh _popup _shadow" class="swhvrteh _popup _shadow"
:style="{ zIndex }" :style="{ zIndex }"
@contextmenu.prevent="() => {}" @contextmenu.prevent="() => {}"
> >
<ol v-if="type === 'user'" ref="suggests" class="users"> <ol v-if="type === 'user'" ref="suggests" class="users">
<li <li
v-for="user in users" v-for="user in users"
tabindex="-1" tabindex="-1"
class="user" class="user"
@click="complete(type, user)" @click="complete(type, user)"
@keydown="onKeydown" @keydown="onKeydown"
> >
<img class="avatar" :src="user.avatarUrl" /> <img class="avatar" :src="user.avatarUrl" />
<span class="name"> <span class="name">
<MkUserName :key="user.id" :user="user" /> <MkUserName :key="user.id" :user="user" />
</span> </span>
<span class="username">@{{ acct(user) }}</span> <span class="username">@{{ acct(user) }}</span>
</li> </li>
<li <li
tabindex="-1" tabindex="-1"
class="choose" class="choose"
@click="chooseUser()" @click="chooseUser()"
@keydown="onKeydown" @keydown="onKeydown"
> >
{{ i18n.ts.selectUser }} {{ i18n.ts.selectUser }}
</li> </li>
</ol> </ol>
<ol v-else-if="hashtags.length > 0" ref="suggests" class="hashtags"> <ol v-else-if="hashtags.length > 0" ref="suggests" class="hashtags">
<li <li
v-for="hashtag in hashtags" v-for="hashtag in hashtags"
tabindex="-1" tabindex="-1"
@click="complete(type, hashtag)" @click="complete(type, hashtag)"
@keydown="onKeydown" @keydown="onKeydown"
> >
<span class="name">{{ hashtag }}</span> <span class="name">{{ hashtag }}</span>
</li> </li>
</ol> </ol>
<ol v-else-if="emojis.length > 0" ref="suggests" class="emojis"> <ol v-else-if="emojis.length > 0" ref="suggests" class="emojis">
<li <li
v-for="emoji in emojis" v-for="emoji in emojis"
tabindex="-1" tabindex="-1"
@click="complete(type, emoji.emoji)" @click="complete(type, emoji.emoji)"
@keydown="onKeydown" @keydown="onKeydown"
> >
<span v-if="emoji.isCustomEmoji" class="emoji" <span v-if="emoji.isCustomEmoji" class="emoji"
><img ><img
:src=" :src="
defaultStore.state.disableShowingAnimatedImages defaultStore.state.disableShowingAnimatedImages
? getStaticImageUrl(emoji.url) ? getStaticImageUrl(emoji.url)
: emoji.url : emoji.url
" "
:alt="emoji.emoji" :alt="emoji.emoji"
/></span> /></span>
<span <span
v-else-if="!defaultStore.state.useOsNativeEmojis" v-else-if="!defaultStore.state.useOsNativeEmojis"
class="emoji" class="emoji"
><img :src="emoji.url" :alt="emoji.emoji" ><img :src="emoji.url" :alt="emoji.emoji"
/></span> /></span>
<span v-else class="emoji">{{ emoji.emoji }}</span> <span v-else class="emoji">{{ emoji.emoji }}</span>
<span <span
class="name" class="name"
v-html="emoji.name.replace(q, `<b>${q}</b>`)" v-html="emoji.name.replace(q, `<b>${q}</b>`)"
></span> ></span>
<span v-if="emoji.aliasOf" class="alias" <span v-if="emoji.aliasOf" class="alias"
>({{ emoji.aliasOf }})</span >({{ emoji.aliasOf }})</span
> >
</li> </li>
</ol> </ol>
<ol v-else-if="mfmTags.length > 0" ref="suggests" class="mfmTags"> <ol v-else-if="mfmTags.length > 0" ref="suggests" class="mfmTags">
<li <li
v-for="tag in mfmTags" v-for="tag in mfmTags"
tabindex="-1" tabindex="-1"
@click="complete(type, tag)" @click="complete(type, tag)"
@keydown="onKeydown" @keydown="onKeydown"
> >
<span class="tag">{{ tag }}</span> <span class="tag">{{ tag }}</span>
</li> </li>
</ol> </ol>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { import {
markRaw, markRaw,
ref, ref,
onUpdated, onUpdated,
onMounted, onMounted,
onBeforeUnmount, onBeforeUnmount,
nextTick, nextTick,
watch, watch,
} from "vue"; } from "vue";
import contains from "@/scripts/contains"; import contains from "@/scripts/contains";
import { char2filePath } from "@/scripts/twemoji-base"; import { char2filePath } from "@/scripts/twemoji-base";
@ -104,38 +104,38 @@ import { instance } from "@/instance";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
type EmojiDef = { type EmojiDef = {
emoji: string; emoji: string;
name: string; name: string;
aliasOf?: string; aliasOf?: string;
url?: string; url?: string;
isCustomEmoji?: boolean; isCustomEmoji?: boolean;
}; };
const lib = emojilist.filter((x) => x.category !== "flags"); const lib = emojilist.filter((x) => x.category !== "flags");
for (const emoji of lib) { for (const emoji of lib) {
if (emoji.skin_tone_support) { if (emoji.skin_tone_support) {
emoji.emoji = addSkinTone(emoji.emoji); emoji.emoji = addSkinTone(emoji.emoji);
} }
} }
const emjdb: EmojiDef[] = lib.map((x) => ({ const emjdb: EmojiDef[] = lib.map((x) => ({
emoji: x.emoji, emoji: x.emoji,
name: x.slug, name: x.slug,
url: char2filePath(x.emoji), url: char2filePath(x.emoji),
})); }));
for (const x of lib) { for (const x of lib) {
if (x.keywords) { if (x.keywords) {
for (const k of x.keywords) { for (const k of x.keywords) {
emjdb.push({ emjdb.push({
emoji: x.emoji, emoji: x.emoji,
name: k, name: k,
aliasOf: x.slug, aliasOf: x.slug,
url: char2filePath(x.emoji), url: char2filePath(x.emoji),
}); });
} }
} }
} }
emjdb.sort((a, b) => a.name.length - b.name.length); emjdb.sort((a, b) => a.name.length - b.name.length);
@ -145,24 +145,24 @@ const customEmojis = instance.emojis;
const emojiDefinitions: EmojiDef[] = []; const emojiDefinitions: EmojiDef[] = [];
for (const x of customEmojis) { for (const x of customEmojis) {
emojiDefinitions.push({ emojiDefinitions.push({
name: x.name, name: x.name,
emoji: `:${x.name}:`, emoji: `:${x.name}:`,
url: x.url, url: x.url,
isCustomEmoji: true, isCustomEmoji: true,
}); });
if (x.aliases) { if (x.aliases) {
for (const alias of x.aliases) { for (const alias of x.aliases) {
emojiDefinitions.push({ emojiDefinitions.push({
name: alias, name: alias,
aliasOf: x.name, aliasOf: x.name,
emoji: `:${x.name}:`, emoji: `:${x.name}:`,
url: x.url, url: x.url,
isCustomEmoji: true, isCustomEmoji: true,
}); });
} }
} }
} }
emojiDefinitions.sort((a, b) => a.name.length - b.name.length); emojiDefinitions.sort((a, b) => a.name.length - b.name.length);
@ -171,26 +171,26 @@ const emojiDb = markRaw(emojiDefinitions.concat(emjdb));
//#endregion //#endregion
export default { export default {
emojiDb, emojiDb,
emojiDefinitions, emojiDefinitions,
emojilist, emojilist,
customEmojis, customEmojis,
}; };
</script> </script>
<script lang="ts" setup> <script lang="ts" setup>
const props = defineProps<{ const props = defineProps<{
type: string; type: string;
q: string | null; q: string | null;
textarea: HTMLTextAreaElement; textarea: HTMLTextAreaElement;
close: () => void; close: () => void;
x: number; x: number;
y: number; y: number;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(event: "done", value: { type: string; value: any }): void; (event: "done", value: { type: string; value: any }): void;
(event: "closed"): void; (event: "closed"): void;
}>(); }>();
const suggests = ref<Element>(); const suggests = ref<Element>();
@ -206,359 +206,359 @@ const select = ref(-1);
const zIndex = os.claimZIndex("high"); const zIndex = os.claimZIndex("high");
function complete(type: string, value: any) { function complete(type: string, value: any) {
emit("done", { type, value }); emit("done", { type, value });
emit("closed"); emit("closed");
if (type === "emoji") { if (type === "emoji") {
let recents = defaultStore.state.recentlyUsedEmojis; let recents = defaultStore.state.recentlyUsedEmojis;
recents = recents.filter((emoji: any) => emoji !== value); recents = recents.filter((emoji: any) => emoji !== value);
recents.unshift(value); recents.unshift(value);
defaultStore.set("recentlyUsedEmojis", recents.splice(0, 32)); defaultStore.set("recentlyUsedEmojis", recents.splice(0, 32));
} }
} }
function setPosition() { function setPosition() {
if (!rootEl.value) return; if (!rootEl.value) return;
if (props.x + rootEl.value.offsetWidth > window.innerWidth) { if (props.x + rootEl.value.offsetWidth > window.innerWidth) {
rootEl.value.style.left = rootEl.value.style.left =
window.innerWidth - rootEl.value.offsetWidth + "px"; window.innerWidth - rootEl.value.offsetWidth + "px";
} else { } else {
rootEl.value.style.left = `${props.x}px`; rootEl.value.style.left = `${props.x}px`;
} }
if (props.y + rootEl.value.offsetHeight > window.innerHeight) { if (props.y + rootEl.value.offsetHeight > window.innerHeight) {
rootEl.value.style.top = props.y - rootEl.value.offsetHeight + "px"; rootEl.value.style.top = props.y - rootEl.value.offsetHeight + "px";
rootEl.value.style.marginTop = "0"; rootEl.value.style.marginTop = "0";
} else { } else {
rootEl.value.style.top = props.y + "px"; rootEl.value.style.top = props.y + "px";
rootEl.value.style.marginTop = "calc(1em + 8px)"; rootEl.value.style.marginTop = "calc(1em + 8px)";
} }
} }
function exec() { function exec() {
select.value = -1; select.value = -1;
if (suggests.value) { if (suggests.value) {
for (const el of Array.from(items.value)) { for (const el of Array.from(items.value)) {
el.removeAttribute("data-selected"); el.removeAttribute("data-selected");
} }
} }
if (props.type === "user") { if (props.type === "user") {
if (!props.q) { if (!props.q) {
users.value = []; users.value = [];
fetching.value = false; fetching.value = false;
return; return;
} }
const cacheKey = `autocomplete:user:${props.q}`; const cacheKey = `autocomplete:user:${props.q}`;
const cache = sessionStorage.getItem(cacheKey); const cache = sessionStorage.getItem(cacheKey);
if (cache) { if (cache) {
users.value = JSON.parse(cache); users.value = JSON.parse(cache);
fetching.value = false; fetching.value = false;
} else { } else {
os.api("users/search-by-username-and-host", { os.api("users/search-by-username-and-host", {
username: props.q, username: props.q,
limit: 10, limit: 10,
detail: false, detail: false,
}).then((searchedUsers) => { }).then((searchedUsers) => {
users.value = searchedUsers as any[]; users.value = searchedUsers as any[];
fetching.value = false; fetching.value = false;
// //
sessionStorage.setItem(cacheKey, JSON.stringify(searchedUsers)); sessionStorage.setItem(cacheKey, JSON.stringify(searchedUsers));
}); });
} }
} else if (props.type === "hashtag") { } else if (props.type === "hashtag") {
if (!props.q || props.q === "") { if (!props.q || props.q === "") {
hashtags.value = JSON.parse( hashtags.value = JSON.parse(
localStorage.getItem("hashtags") || "[]" localStorage.getItem("hashtags") || "[]"
); );
fetching.value = false; fetching.value = false;
} else { } else {
const cacheKey = `autocomplete:hashtag:${props.q}`; const cacheKey = `autocomplete:hashtag:${props.q}`;
const cache = sessionStorage.getItem(cacheKey); const cache = sessionStorage.getItem(cacheKey);
if (cache) { if (cache) {
const hashtags = JSON.parse(cache); const hashtags = JSON.parse(cache);
hashtags.value = hashtags; hashtags.value = hashtags;
fetching.value = false; fetching.value = false;
} else { } else {
os.api("hashtags/search", { os.api("hashtags/search", {
query: props.q, query: props.q,
limit: 30, limit: 30,
}).then((searchedHashtags) => { }).then((searchedHashtags) => {
hashtags.value = searchedHashtags as any[]; hashtags.value = searchedHashtags as any[];
fetching.value = false; fetching.value = false;
// //
sessionStorage.setItem( sessionStorage.setItem(
cacheKey, cacheKey,
JSON.stringify(searchedHashtags) JSON.stringify(searchedHashtags)
); );
}); });
} }
} }
} else if (props.type === "emoji") { } else if (props.type === "emoji") {
if (!props.q || props.q === "") { if (!props.q || props.q === "") {
// 使 // 使
emojis.value = defaultStore.state.recentlyUsedEmojis emojis.value = defaultStore.state.recentlyUsedEmojis
.map((emoji) => .map((emoji) =>
emojiDb.find((dbEmoji) => dbEmoji.emoji === emoji) emojiDb.find((dbEmoji) => dbEmoji.emoji === emoji)
) )
.filter((x) => x) as EmojiDef[]; .filter((x) => x) as EmojiDef[];
return; return;
} }
const matched: EmojiDef[] = []; const matched: EmojiDef[] = [];
const max = 30; const max = 30;
emojiDb.some((x) => { emojiDb.some((x) => {
if ( if (
x.name.startsWith(props.q ?? "") && x.name.startsWith(props.q ?? "") &&
!x.aliasOf && !x.aliasOf &&
!matched.some((y) => y.emoji === x.emoji) !matched.some((y) => y.emoji === x.emoji)
) )
matched.push(x); matched.push(x);
return matched.length === max; return matched.length === max;
}); });
if (matched.length < max) { if (matched.length < max) {
emojiDb.some((x) => { emojiDb.some((x) => {
if ( if (
x.name.startsWith(props.q ?? "") && x.name.startsWith(props.q ?? "") &&
!matched.some((y) => y.emoji === x.emoji) !matched.some((y) => y.emoji === x.emoji)
) )
matched.push(x); matched.push(x);
return matched.length === max; return matched.length === max;
}); });
} }
if (matched.length < max) { if (matched.length < max) {
emojiDb.some((x) => { emojiDb.some((x) => {
if ( if (
x.name.includes(props.q ?? "") && x.name.includes(props.q ?? "") &&
!matched.some((y) => y.emoji === x.emoji) !matched.some((y) => y.emoji === x.emoji)
) )
matched.push(x); matched.push(x);
return matched.length === max; return matched.length === max;
}); });
} }
emojis.value = matched; emojis.value = matched;
} else if (props.type === "mfmTag") { } else if (props.type === "mfmTag") {
if (!props.q || props.q === "") { if (!props.q || props.q === "") {
mfmTags.value = MFM_TAGS; mfmTags.value = MFM_TAGS;
return; return;
} }
mfmTags.value = MFM_TAGS.filter((tag) => tag.startsWith(props.q ?? "")); mfmTags.value = MFM_TAGS.filter((tag) => tag.startsWith(props.q ?? ""));
} }
} }
function onMousedown(event: Event) { function onMousedown(event: Event) {
if (!contains(rootEl.value, event.target) && rootEl.value !== event.target) if (!contains(rootEl.value, event.target) && rootEl.value !== event.target)
props.close(); props.close();
} }
function onKeydown(event: KeyboardEvent) { function onKeydown(event: KeyboardEvent) {
const cancel = () => { const cancel = () => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
}; };
switch (event.key) { switch (event.key) {
case "Enter": case "Enter":
if (select.value !== -1) { if (select.value !== -1) {
cancel(); cancel();
(items.value[select.value] as any).click(); (items.value[select.value] as any).click();
} else { } else {
props.close(); props.close();
} }
break; break;
case "Escape": case "Escape":
cancel(); cancel();
props.close(); props.close();
break; break;
case "ArrowUp": case "ArrowUp":
if (select.value !== -1) { if (select.value !== -1) {
cancel(); cancel();
selectPrev(); selectPrev();
} else { } else {
props.close(); props.close();
} }
break; break;
case "Tab": case "Tab":
case "ArrowDown": case "ArrowDown":
cancel(); cancel();
selectNext(); selectNext();
break; break;
default: default:
event.stopPropagation(); event.stopPropagation();
props.textarea.focus(); props.textarea.focus();
} }
} }
function selectNext() { function selectNext() {
if (++select.value >= items.value.length) select.value = 0; if (++select.value >= items.value.length) select.value = 0;
if (items.value.length === 0) select.value = -1; if (items.value.length === 0) select.value = -1;
applySelect(); applySelect();
} }
function selectPrev() { function selectPrev() {
if (--select.value < 0) select.value = items.value.length - 1; if (--select.value < 0) select.value = items.value.length - 1;
applySelect(); applySelect();
} }
function applySelect() { function applySelect() {
for (const el of Array.from(items.value)) { for (const el of Array.from(items.value)) {
el.removeAttribute("data-selected"); el.removeAttribute("data-selected");
} }
if (select.value !== -1) { if (select.value !== -1) {
items.value[select.value].setAttribute("data-selected", "true"); items.value[select.value].setAttribute("data-selected", "true");
(items.value[select.value] as any).focus(); (items.value[select.value] as any).focus();
} }
} }
function chooseUser() { function chooseUser() {
props.close(); props.close();
os.selectUser().then((user) => { os.selectUser().then((user) => {
complete("user", user); complete("user", user);
props.textarea.focus(); props.textarea.focus();
}); });
} }
onUpdated(() => { onUpdated(() => {
setPosition(); setPosition();
items.value = suggests.value?.children ?? []; items.value = suggests.value?.children ?? [];
}); });
onMounted(() => { onMounted(() => {
setPosition(); setPosition();
props.textarea.addEventListener("keydown", onKeydown); props.textarea.addEventListener("keydown", onKeydown);
for (const el of Array.from(document.querySelectorAll("body *"))) { for (const el of Array.from(document.querySelectorAll("body *"))) {
el.addEventListener("mousedown", onMousedown); el.addEventListener("mousedown", onMousedown);
} }
nextTick(() => { nextTick(() => {
exec(); exec();
watch( watch(
() => props.q, () => props.q,
() => { () => {
nextTick(() => { nextTick(() => {
exec(); exec();
}); });
} }
); );
}); });
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
props.textarea.removeEventListener("keydown", onKeydown); props.textarea.removeEventListener("keydown", onKeydown);
for (const el of Array.from(document.querySelectorAll("body *"))) { for (const el of Array.from(document.querySelectorAll("body *"))) {
el.removeEventListener("mousedown", onMousedown); el.removeEventListener("mousedown", onMousedown);
} }
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.swhvrteh { .swhvrteh {
position: fixed; position: fixed;
max-width: 100%; max-width: 100%;
margin-top: calc(1em + 8px); margin-top: calc(1em + 8px);
overflow: hidden; overflow: hidden;
transition: top 0.1s ease, left 0.1s ease; transition: top 0.1s ease, left 0.1s ease;
> ol { > ol {
display: block; display: block;
margin: 0; margin: 0;
padding: 4px 0; padding: 4px 0;
max-height: 190px; max-height: 190px;
max-width: 500px; max-width: 500px;
overflow: auto; overflow: auto;
list-style: none; list-style: none;
> li { > li {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 4px 12px; padding: 4px 12px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
font-size: 0.9em; font-size: 0.9em;
cursor: default; cursor: default;
&, &,
* { * {
user-select: none; user-select: none;
} }
* { * {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
&:hover { &:hover {
background: var(--X3); background: var(--X3);
} }
&[data-selected="true"] { &[data-selected="true"] {
background: var(--accent); background: var(--accent);
&, &,
* { * {
color: #fff !important; color: #fff !important;
} }
} }
&:active { &:active {
background: var(--accentDarken); background: var(--accentDarken);
&, &,
* { * {
color: #fff !important; color: #fff !important;
} }
} }
} }
} }
> .users > li { > .users > li {
.avatar { .avatar {
min-width: 28px; min-width: 28px;
min-height: 28px; min-height: 28px;
max-width: 28px; max-width: 28px;
max-height: 28px; max-height: 28px;
margin: 0 8px 0 0; margin: 0 8px 0 0;
border-radius: 100%; border-radius: 100%;
} }
.name { .name {
margin: 0 8px 0 0; margin: 0 8px 0 0;
} }
} }
> .emojis > li { > .emojis > li {
.emoji { .emoji {
display: inline-block; display: inline-block;
margin: 0 4px 0 0; margin: 0 4px 0 0;
width: 24px; width: 24px;
> img { > img {
width: 24px; width: 24px;
vertical-align: bottom; vertical-align: bottom;
} }
} }
.alias { .alias {
margin: 0 0 0 8px; margin: 0 0 0 8px;
} }
} }
> .mfmTags > li { > .mfmTags > li {
.name { .name {
} }
} }
} }
</style> </style>

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="defgtij"> <div class="defgtij">
<div v-for="user in users" :key="user.id" class="avatar-holder"> <div v-for="user in users" :key="user.id" class="avatar-holder">
<MkAvatar :user="user" :show-indicator="true" class="avatar" /> <MkAvatar :user="user" :show-indicator="true" class="avatar" />
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -11,34 +11,34 @@ import { onMounted, ref } from "vue";
import * as os from "@/os"; import * as os from "@/os";
const props = defineProps<{ const props = defineProps<{
userIds: string[]; userIds: string[];
}>(); }>();
const users = ref([]); const users = ref([]);
onMounted(async () => { onMounted(async () => {
users.value = await os.api("users/show", { users.value = await os.api("users/show", {
userIds: props.userIds, userIds: props.userIds,
}); });
}); });
</script> </script>
<style lang="scss"> <style lang="scss">
.defgtij { .defgtij {
padding: 12px; padding: 12px;
grid-gap: 12px; grid-gap: 12px;
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(30px, 40px)); grid-template-columns: repeat(auto-fill, minmax(30px, 40px));
place-content: center; place-content: center;
> .avatar-holder { > .avatar-holder {
aspect-ratio: 1; aspect-ratio: 1;
> .avatar { > .avatar {
width: 100%; width: 100%;
height: 100%; height: 100%;
aspect-ratio: 1; aspect-ratio: 1;
} }
} }
} }
</style> </style>

View File

@ -1,254 +1,254 @@
<template> <template>
<button <button
v-if="!link" v-if="!link"
class="bghgjjyj _button" class="bghgjjyj _button"
:class="{ inline, primary, gradate, danger, rounded, full, mini, chip }" :class="{ inline, primary, gradate, danger, rounded, full, mini, chip }"
:type="type" :type="type"
@click="emit('click', $event)" @click="emit('click', $event)"
@mousedown="onMousedown" @mousedown="onMousedown"
> >
<div ref="ripples" class="ripples"></div> <div ref="ripples" class="ripples"></div>
<div class="content"> <div class="content">
<slot></slot> <slot></slot>
</div> </div>
</button> </button>
<MkA <MkA
v-else v-else
class="bghgjjyj _button" class="bghgjjyj _button"
:class="{ inline, primary, gradate, danger, rounded, full, mini }" :class="{ inline, primary, gradate, danger, rounded, full, mini }"
:to="to" :to="to"
@mousedown="onMousedown" @mousedown="onMousedown"
> >
<div ref="ripples" class="ripples"></div> <div ref="ripples" class="ripples"></div>
<div class="content"> <div class="content">
<slot></slot> <slot></slot>
</div> </div>
</MkA> </MkA>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted } from "vue"; import { nextTick, onMounted } from "vue";
const props = defineProps<{ const props = defineProps<{
type?: "button" | "submit" | "reset"; type?: "button" | "submit" | "reset";
primary?: boolean; primary?: boolean;
gradate?: boolean; gradate?: boolean;
rounded?: boolean; rounded?: boolean;
inline?: boolean; inline?: boolean;
link?: boolean; link?: boolean;
to?: string; to?: string;
autofocus?: boolean; autofocus?: boolean;
wait?: boolean; wait?: boolean;
danger?: boolean; danger?: boolean;
full?: boolean; full?: boolean;
mini?: boolean; mini?: boolean;
chip?: boolean; chip?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "click", payload: MouseEvent): void; (ev: "click", payload: MouseEvent): void;
}>(); }>();
let el = $ref<HTMLElement | null>(null); let el = $ref<HTMLElement | null>(null);
let ripples = $ref<HTMLElement | null>(null); let ripples = $ref<HTMLElement | null>(null);
onMounted(() => { onMounted(() => {
if (props.autofocus) { if (props.autofocus) {
nextTick(() => { nextTick(() => {
el!.focus(); el!.focus();
}); });
} }
}); });
function distance(p, q): number { function distance(p, q): number {
return Math.hypot(p.x - q.x, p.y - q.y); return Math.hypot(p.x - q.x, p.y - q.y);
} }
function calcCircleScale(boxW, boxH, circleCenterX, circleCenterY): number { function calcCircleScale(boxW, boxH, circleCenterX, circleCenterY): number {
const origin = { x: circleCenterX, y: circleCenterY }; const origin = { x: circleCenterX, y: circleCenterY };
const dist1 = distance({ x: 0, y: 0 }, origin); const dist1 = distance({ x: 0, y: 0 }, origin);
const dist2 = distance({ x: boxW, y: 0 }, origin); const dist2 = distance({ x: boxW, y: 0 }, origin);
const dist3 = distance({ x: 0, y: boxH }, origin); const dist3 = distance({ x: 0, y: boxH }, origin);
const dist4 = distance({ x: boxW, y: boxH }, origin); const dist4 = distance({ x: boxW, y: boxH }, origin);
return Math.max(dist1, dist2, dist3, dist4) * 2; return Math.max(dist1, dist2, dist3, dist4) * 2;
} }
function onMousedown(evt: MouseEvent): void { function onMousedown(evt: MouseEvent): void {
const target = evt.target! as HTMLElement; const target = evt.target! as HTMLElement;
const rect = target.getBoundingClientRect(); const rect = target.getBoundingClientRect();
const ripple = document.createElement("div"); const ripple = document.createElement("div");
ripple.style.top = (evt.clientY - rect.top - 1).toString() + "px"; ripple.style.top = (evt.clientY - rect.top - 1).toString() + "px";
ripple.style.left = (evt.clientX - rect.left - 1).toString() + "px"; ripple.style.left = (evt.clientX - rect.left - 1).toString() + "px";
ripples!.appendChild(ripple); ripples!.appendChild(ripple);
const circleCenterX = evt.clientX - rect.left; const circleCenterX = evt.clientX - rect.left;
const circleCenterY = evt.clientY - rect.top; const circleCenterY = evt.clientY - rect.top;
const scale = calcCircleScale( const scale = calcCircleScale(
target.clientWidth, target.clientWidth,
target.clientHeight, target.clientHeight,
circleCenterX, circleCenterX,
circleCenterY circleCenterY
); );
window.setTimeout(() => { window.setTimeout(() => {
ripple.style.transform = "scale(" + scale / 2 + ")"; ripple.style.transform = "scale(" + scale / 2 + ")";
}, 1); }, 1);
window.setTimeout(() => { window.setTimeout(() => {
ripple.style.transition = "all 1s ease"; ripple.style.transition = "all 1s ease";
ripple.style.opacity = "0"; ripple.style.opacity = "0";
}, 1000); }, 1000);
window.setTimeout(() => { window.setTimeout(() => {
if (ripples) ripples.removeChild(ripple); if (ripples) ripples.removeChild(ripple);
}, 2000); }, 2000);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.bghgjjyj { .bghgjjyj {
position: relative; position: relative;
z-index: 1; // box-shadow z-index: 1; // box-shadow
display: block; display: block;
min-width: 100px; min-width: 100px;
min-height: 35px; min-height: 35px;
width: max-content; width: max-content;
padding: 8px 16px; padding: 8px 16px;
text-align: center; text-align: center;
font-weight: normal; font-weight: normal;
font-size: max(12px, 1em); font-size: max(12px, 1em);
box-shadow: none; box-shadow: none;
text-decoration: none; text-decoration: none;
background: var(--buttonBg); background: var(--buttonBg);
border-radius: 5px; border-radius: 5px;
overflow: clip; overflow: clip;
box-sizing: border-box; box-sizing: border-box;
transition: background 0.1s ease; transition: background 0.1s ease;
margin-right: 0.2rem; margin-right: 0.2rem;
margin-left: 0.2rem; margin-left: 0.2rem;
&:not(:disabled):hover { &:not(:disabled):hover {
background: var(--buttonHoverBg); background: var(--buttonHoverBg);
} }
&:not(:disabled):active { &:not(:disabled):active {
background: var(--buttonHoverBg); background: var(--buttonHoverBg);
} }
&.full { &.full {
width: 100%; width: 100%;
} }
&.rounded { &.rounded {
border-radius: 999px; border-radius: 999px;
} }
&.primary { &.primary {
font-weight: bold; font-weight: bold;
color: var(--fgOnAccent) !important; color: var(--fgOnAccent) !important;
background: var(--accent); background: var(--accent);
&:not(:disabled):hover { &:not(:disabled):hover {
background: var(--X8); background: var(--X8);
} }
&:not(:disabled):active { &:not(:disabled):active {
background: var(--X8); background: var(--X8);
} }
} }
&.gradate { &.gradate {
font-weight: bold; font-weight: bold;
color: var(--fgOnAccent) !important; color: var(--fgOnAccent) !important;
background: linear-gradient( background: linear-gradient(
90deg, 90deg,
var(--buttonGradateA), var(--buttonGradateA),
var(--buttonGradateB) var(--buttonGradateB)
); );
&:not(:disabled):hover { &:not(:disabled):hover {
background: linear-gradient(90deg, var(--X8), var(--X8)); background: linear-gradient(90deg, var(--X8), var(--X8));
} }
&:not(:disabled):active { &:not(:disabled):active {
background: linear-gradient(90deg, var(--X8), var(--X8)); background: linear-gradient(90deg, var(--X8), var(--X8));
} }
} }
&.danger { &.danger {
color: #eb6f92; color: #eb6f92;
&.primary { &.primary {
color: #e0def4; color: #e0def4;
background: #eb6f92; background: #eb6f92;
&:not(:disabled):hover { &:not(:disabled):hover {
background: #eb6f92; background: #eb6f92;
} }
&:not(:disabled):active { &:not(:disabled):active {
background: #b4637a; background: #b4637a;
} }
} }
} }
&.mini { &.mini {
padding: 4px 8px; padding: 4px 8px;
font-size: max(12px, 0.9em); font-size: max(12px, 0.9em);
border-radius: 100px; border-radius: 100px;
} }
&.chip { &.chip {
padding: 4px 12px; padding: 4px 12px;
font-size: max(12px, 0.9em); font-size: max(12px, 0.9em);
min-width: unset; min-width: unset;
border-radius: 100px; border-radius: 100px;
} }
&:disabled { &:disabled {
opacity: 0.7; opacity: 0.7;
} }
&:focus-visible { &:focus-visible {
outline: auto; outline: auto;
} }
&.inline { &.inline {
display: inline-block; display: inline-block;
width: auto; width: auto;
min-width: 100px; min-width: 100px;
} }
> .ripples { > .ripples {
position: absolute; position: absolute;
z-index: 0; z-index: 0;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 6px; border-radius: 6px;
overflow: hidden; overflow: hidden;
::v-deep(div) { ::v-deep(div) {
position: absolute; position: absolute;
width: 2px; width: 2px;
height: 2px; height: 2px;
border-radius: 100%; border-radius: 100%;
background: rgba(0, 0, 0, 0.1); background: rgba(0, 0, 0, 0.1);
opacity: 1; opacity: 1;
transform: scale(1); transform: scale(1);
transition: all 0.5s cubic-bezier(0, 0.5, 0, 1); transition: all 0.5s cubic-bezier(0, 0.5, 0, 1);
} }
} }
&.primary > .ripples ::v-deep(div) { &.primary > .ripples ::v-deep(div) {
background: rgba(0, 0, 0, 0.15); background: rgba(0, 0, 0, 0.15);
} }
> .content { > .content {
position: relative; position: relative;
z-index: 1; z-index: 1;
} }
} }
</style> </style>

View File

@ -1,8 +1,8 @@
<template> <template>
<div> <div>
<span v-if="!available">{{ i18n.ts.waiting }}<MkEllipsis /></span> <span v-if="!available">{{ i18n.ts.waiting }}<MkEllipsis /></span>
<div ref="captchaEl"></div> <div ref="captchaEl"></div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -11,46 +11,46 @@ import { defaultStore } from "@/store";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
type Captcha = { type Captcha = {
render( render(
container: string | Node, container: string | Node,
options: { options: {
readonly [_ in readonly [_ in
| "sitekey" | "sitekey"
| "theme" | "theme"
| "type" | "type"
| "size" | "size"
| "tabindex" | "tabindex"
| "callback" | "callback"
| "expired" | "expired"
| "expired-callback" | "expired-callback"
| "error-callback" | "error-callback"
| "endpoint"]?: unknown; | "endpoint"]?: unknown;
} }
): string; ): string;
remove(id: string): void; remove(id: string): void;
execute(id: string): void; execute(id: string): void;
reset(id?: string): void; reset(id?: string): void;
getResponse(id: string): string; getResponse(id: string): string;
}; };
type CaptchaProvider = "hcaptcha" | "recaptcha"; type CaptchaProvider = "hcaptcha" | "recaptcha";
type CaptchaContainer = { type CaptchaContainer = {
readonly [_ in CaptchaProvider]?: Captcha; readonly [_ in CaptchaProvider]?: Captcha;
}; };
declare global { declare global {
interface Window extends CaptchaContainer {} interface Window extends CaptchaContainer {}
} }
const props = defineProps<{ const props = defineProps<{
provider: CaptchaProvider; provider: CaptchaProvider;
sitekey: string; sitekey: string;
modelValue?: string | null; modelValue?: string | null;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "update:modelValue", v: string | null): void; (ev: "update:modelValue", v: string | null): void;
}>(); }>();
const available = ref(false); const available = ref(false);
@ -58,79 +58,79 @@ const available = ref(false);
const captchaEl = ref<HTMLDivElement | undefined>(); const captchaEl = ref<HTMLDivElement | undefined>();
const variable = computed(() => { const variable = computed(() => {
switch (props.provider) { switch (props.provider) {
case "hcaptcha": case "hcaptcha":
return "hcaptcha"; return "hcaptcha";
case "recaptcha": case "recaptcha":
return "grecaptcha"; return "grecaptcha";
} }
}); });
const loaded = !!window[variable.value]; const loaded = !!window[variable.value];
const src = computed(() => { const src = computed(() => {
switch (props.provider) { switch (props.provider) {
case "hcaptcha": case "hcaptcha":
return "https://js.hcaptcha.com/1/api.js?render=explicit&recaptchacompat=off"; return "https://js.hcaptcha.com/1/api.js?render=explicit&recaptchacompat=off";
case "recaptcha": case "recaptcha":
return "https://www.recaptcha.net/recaptcha/api.js?render=explicit"; return "https://www.recaptcha.net/recaptcha/api.js?render=explicit";
} }
}); });
const captcha = computed<Captcha>( const captcha = computed<Captcha>(
() => window[variable.value] || ({} as unknown as Captcha) () => window[variable.value] || ({} as unknown as Captcha)
); );
if (loaded) { if (loaded) {
available.value = true; available.value = true;
} else { } else {
( (
document.getElementById(props.provider) || document.getElementById(props.provider) ||
document.head.appendChild( document.head.appendChild(
Object.assign(document.createElement("script"), { Object.assign(document.createElement("script"), {
async: true, async: true,
id: props.provider, id: props.provider,
src: src.value, src: src.value,
}) })
) )
).addEventListener("load", () => (available.value = true)); ).addEventListener("load", () => (available.value = true));
} }
function reset() { function reset() {
if (captcha.value.reset) captcha.value.reset(); if (captcha.value.reset) captcha.value.reset();
} }
function requestRender() { function requestRender() {
if (captcha.value.render && captchaEl.value instanceof Element) { if (captcha.value.render && captchaEl.value instanceof Element) {
captcha.value.render(captchaEl.value, { captcha.value.render(captchaEl.value, {
sitekey: props.sitekey, sitekey: props.sitekey,
theme: defaultStore.state.darkMode ? "dark" : "light", theme: defaultStore.state.darkMode ? "dark" : "light",
callback: callback, callback: callback,
"expired-callback": callback, "expired-callback": callback,
"error-callback": callback, "error-callback": callback,
}); });
} else { } else {
window.setTimeout(requestRender, 1); window.setTimeout(requestRender, 1);
} }
} }
function callback(response?: string) { function callback(response?: string) {
emit("update:modelValue", typeof response === "string" ? response : null); emit("update:modelValue", typeof response === "string" ? response : null);
} }
onMounted(() => { onMounted(() => {
if (available.value) { if (available.value) {
requestRender(); requestRender();
} else { } else {
watch(available, requestRender); watch(available, requestRender);
} }
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
reset(); reset();
}); });
defineExpose({ defineExpose({
reset, reset,
}); });
</script> </script>

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +1,30 @@
<template> <template>
<MkTooltip <MkTooltip
ref="tooltip" ref="tooltip"
:showing="showing" :showing="showing"
:x="x" :x="x"
:y="y" :y="y"
:max-width="340" :max-width="340"
:direction="'top'" :direction="'top'"
:inner-margin="16" :inner-margin="16"
@closed="emit('closed')" @closed="emit('closed')"
> >
<div v-if="title || series" class="qpcyisrl"> <div v-if="title || series" class="qpcyisrl">
<div v-if="title" class="title">{{ title }}</div> <div v-if="title" class="title">{{ title }}</div>
<template v-if="series"> <template v-if="series">
<div v-for="x in series" class="series"> <div v-for="x in series" class="series">
<span <span
class="color" class="color"
:style="{ :style="{
background: x.backgroundColor, background: x.backgroundColor,
borderColor: x.borderColor, borderColor: x.borderColor,
}" }"
></span> ></span>
<span>{{ x.text }}</span> <span>{{ x.text }}</span>
</div> </div>
</template> </template>
</div> </div>
</MkTooltip> </MkTooltip>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -32,37 +32,37 @@ import {} from "vue";
import MkTooltip from "./MkTooltip.vue"; import MkTooltip from "./MkTooltip.vue";
const props = defineProps<{ const props = defineProps<{
showing: boolean; showing: boolean;
x: number; x: number;
y: number; y: number;
title?: string; title?: string;
series?: { series?: {
backgroundColor: string; backgroundColor: string;
borderColor: string; borderColor: string;
text: string; text: string;
}[]; }[];
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "closed"): void; (ev: "closed"): void;
}>(); }>();
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.qpcyisrl { .qpcyisrl {
> .title { > .title {
margin-bottom: 4px; margin-bottom: 4px;
} }
> .series { > .series {
> .color { > .color {
display: inline-block; display: inline-block;
width: 8px; width: 8px;
height: 8px; height: 8px;
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
margin-right: 8px; margin-right: 8px;
} }
} }
} }
</style> </style>

View File

@ -1,13 +1,13 @@
<template> <template>
<XModalWindow <XModalWindow
ref="dialog" ref="dialog"
:width="600" :width="600"
@close="dialog?.close()" @close="dialog?.close()"
@closed="$emit('closed')" @closed="$emit('closed')"
> >
<template #header>{{ i18n.ts._mfm.cheatSheet }}</template> <template #header>{{ i18n.ts._mfm.cheatSheet }}</template>
<XCheatSheet :popup="true" style="background: var(--bg)" /> <XCheatSheet :popup="true" style="background: var(--bg)" />
</XModalWindow> </XModalWindow>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -16,24 +16,24 @@ import XCheatSheet from "@/pages/mfm-cheat-sheet.vue";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
const emit = defineEmits<{ const emit = defineEmits<{
(ev: "done"): void; (ev: "done"): void;
(ev: "closed"): void; (ev: "closed"): void;
}>(); }>();
const dialog = $ref<InstanceType<typeof XModalWindow>>(); const dialog = $ref<InstanceType<typeof XModalWindow>>();
function close(res) { function close(res) {
dialog.close(); dialog.close();
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.fade-enter-active, .fade-enter-active,
.fade-leave-active { .fade-leave-active {
transition: opacity 0.2s ease-in-out; transition: opacity 0.2s ease-in-out;
} }
.fade-enter-from, .fade-enter-from,
.fade-leave-to { .fade-leave-to {
opacity: 0; opacity: 0;
} }
</style> </style>

View File

@ -1,9 +1,9 @@
<template> <template>
<code v-if="inline" :class="`language-${prismLang}`" v-html="html"></code> <code v-if="inline" :class="`language-${prismLang}`" v-html="html"></code>
<pre <pre
v-else v-else
:class="`language-${prismLang}`" :class="`language-${prismLang}`"
><code :class="`language-${prismLang}`" v-html="html"></code></pre> ><code :class="`language-${prismLang}`" v-html="html"></code></pre>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -12,19 +12,19 @@ import Prism from "prismjs";
import "prismjs/themes/prism-okaidia.css"; import "prismjs/themes/prism-okaidia.css";
const props = defineProps<{ const props = defineProps<{
code: string; code: string;
lang?: string; lang?: string;
inline?: boolean; inline?: boolean;
}>(); }>();
const prismLang = computed(() => const prismLang = computed(() =>
Prism.languages[props.lang] ? props.lang : "js" Prism.languages[props.lang] ? props.lang : "js"
); );
const html = computed(() => const html = computed(() =>
Prism.highlight( Prism.highlight(
props.code, props.code,
Prism.languages[prismLang.value], Prism.languages[prismLang.value],
prismLang.value prismLang.value
) )
); );
</script> </script>

View File

@ -1,17 +1,17 @@
<template> <template>
<XCode :code="code" :lang="lang" :inline="inline" /> <XCode :code="code" :lang="lang" :inline="inline" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineAsyncComponent } from "vue"; import { defineAsyncComponent } from "vue";
defineProps<{ defineProps<{
code: string; code: string;
lang?: string; lang?: string;
inline?: boolean; inline?: boolean;
}>(); }>();
const XCode = defineAsyncComponent( const XCode = defineAsyncComponent(
() => import("@/components/MkCode.core.vue") () => import("@/components/MkCode.core.vue")
); );
</script> </script>

View File

@ -1,62 +1,62 @@
<template> <template>
<div <div
v-size="{ max: [380] }" v-size="{ max: [380] }"
class="ukygtjoj _panel" class="ukygtjoj _panel"
:class="{ :class="{
naked, naked,
thin, thin,
hideHeader: !showHeader, hideHeader: !showHeader,
scrollable, scrollable,
closed: !showBody, closed: !showBody,
}" }"
> >
<header v-if="showHeader" ref="header"> <header v-if="showHeader" ref="header">
<div class="title"><slot name="header"></slot></div> <div class="title"><slot name="header"></slot></div>
<div class="sub"> <div class="sub">
<slot name="func"></slot> <slot name="func"></slot>
<button <button
v-if="foldable" v-if="foldable"
class="_button" class="_button"
@click="() => (showBody = !showBody)" @click="() => (showBody = !showBody)"
> >
<template v-if="showBody" <template v-if="showBody"
><i class="ph-caret-up ph-bold ph-lg"></i ><i class="ph-caret-up ph-bold ph-lg"></i
></template> ></template>
<template v-else <template v-else
><i class="ph-caret-down ph-bold ph-lg"></i ><i class="ph-caret-down ph-bold ph-lg"></i
></template> ></template>
</button> </button>
</div> </div>
</header> </header>
<transition <transition
:name="$store.state.animation ? 'container-toggle' : ''" :name="$store.state.animation ? 'container-toggle' : ''"
@enter="enter" @enter="enter"
@after-enter="afterEnter" @after-enter="afterEnter"
@leave="leave" @leave="leave"
@after-leave="afterLeave" @after-leave="afterLeave"
> >
<div <div
v-show="showBody" v-show="showBody"
ref="content" ref="content"
class="content" class="content"
:class="{ omitted }" :class="{ omitted }"
> >
<slot></slot> <slot></slot>
<button <button
v-if="omitted" v-if="omitted"
class="fade _button" class="fade _button"
@click=" @click="
() => { () => {
ignoreOmit = true; ignoreOmit = true;
omitted = false; omitted = false;
} }
" "
> >
<span>{{ i18n.ts.showMore }}</span> <span>{{ i18n.ts.showMore }}</span>
</button> </button>
</div> </div>
</transition> </transition>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -64,245 +64,245 @@ import { defineComponent } from "vue";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
export default defineComponent({ export default defineComponent({
props: { props: {
showHeader: { showHeader: {
type: Boolean, type: Boolean,
required: false, required: false,
default: true, default: true,
}, },
thin: { thin: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
naked: { naked: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
foldable: { foldable: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
expanded: { expanded: {
type: Boolean, type: Boolean,
required: false, required: false,
default: true, default: true,
}, },
scrollable: { scrollable: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
maxHeight: { maxHeight: {
type: Number, type: Number,
required: false, required: false,
default: null, default: null,
}, },
}, },
data() { data() {
return { return {
showBody: this.expanded, showBody: this.expanded,
omitted: null, omitted: null,
ignoreOmit: false, ignoreOmit: false,
i18n, i18n,
}; };
}, },
mounted() { mounted() {
this.$watch( this.$watch(
"showBody", "showBody",
(showBody) => { (showBody) => {
const headerHeight = this.showHeader const headerHeight = this.showHeader
? this.$refs.header.offsetHeight ? this.$refs.header.offsetHeight
: 0; : 0;
this.$el.style.minHeight = `${headerHeight}px`; this.$el.style.minHeight = `${headerHeight}px`;
if (showBody) { if (showBody) {
this.$el.style.flexBasis = "auto"; this.$el.style.flexBasis = "auto";
} else { } else {
this.$el.style.flexBasis = `${headerHeight}px`; this.$el.style.flexBasis = `${headerHeight}px`;
} }
}, },
{ {
immediate: true, immediate: true,
} }
); );
this.$el.style.setProperty("--maxHeight", this.maxHeight + "px"); this.$el.style.setProperty("--maxHeight", this.maxHeight + "px");
const calcOmit = () => { const calcOmit = () => {
if (this.omitted || this.ignoreOmit || this.maxHeight == null) if (this.omitted || this.ignoreOmit || this.maxHeight == null)
return; return;
const height = this.$refs.content.offsetHeight; const height = this.$refs.content.offsetHeight;
this.omitted = height > this.maxHeight; this.omitted = height > this.maxHeight;
}; };
calcOmit(); calcOmit();
new ResizeObserver((entries, observer) => { new ResizeObserver((entries, observer) => {
calcOmit(); calcOmit();
}).observe(this.$refs.content); }).observe(this.$refs.content);
}, },
methods: { methods: {
toggleContent(show: boolean) { toggleContent(show: boolean) {
if (!this.foldable) return; if (!this.foldable) return;
this.showBody = show; this.showBody = show;
}, },
enter(el) { enter(el) {
const elementHeight = el.getBoundingClientRect().height; const elementHeight = el.getBoundingClientRect().height;
el.style.height = 0; el.style.height = 0;
el.offsetHeight; // reflow el.offsetHeight; // reflow
el.style.height = elementHeight + "px"; el.style.height = elementHeight + "px";
}, },
afterEnter(el) { afterEnter(el) {
el.style.height = null; el.style.height = null;
}, },
leave(el) { leave(el) {
const elementHeight = el.getBoundingClientRect().height; const elementHeight = el.getBoundingClientRect().height;
el.style.height = elementHeight + "px"; el.style.height = elementHeight + "px";
el.offsetHeight; // reflow el.offsetHeight; // reflow
el.style.height = 0; el.style.height = 0;
}, },
afterLeave(el) { afterLeave(el) {
el.style.height = null; el.style.height = null;
}, },
}, },
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.container-toggle-enter-active, .container-toggle-enter-active,
.container-toggle-leave-active { .container-toggle-leave-active {
overflow-y: hidden; overflow-y: hidden;
transition: opacity 0.5s, height 0.5s !important; transition: opacity 0.5s, height 0.5s !important;
} }
.container-toggle-enter-from { .container-toggle-enter-from {
opacity: 0; opacity: 0;
} }
.container-toggle-leave-to { .container-toggle-leave-to {
opacity: 0; opacity: 0;
} }
.ukygtjoj { .ukygtjoj {
position: relative; position: relative;
overflow: clip; overflow: clip;
contain: content; contain: content;
&.naked { &.naked {
background: transparent !important; background: transparent !important;
box-shadow: none !important; box-shadow: none !important;
} }
&.scrollable { &.scrollable {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
> .content { > .content {
overflow: auto; overflow: auto;
} }
} }
> header { > header {
position: sticky; position: sticky;
top: var(--stickyTop, 0px); top: var(--stickyTop, 0px);
left: 0; left: 0;
color: var(--panelHeaderFg); color: var(--panelHeaderFg);
background: var(--panelHeaderBg); background: var(--panelHeaderBg);
border-bottom: solid 0.5px var(--panelHeaderDivider); border-bottom: solid 0.5px var(--panelHeaderDivider);
z-index: 2; z-index: 2;
line-height: 1.4em; line-height: 1.4em;
> .title { > .title {
margin: 0; margin: 0;
padding: 12px 16px; padding: 12px 16px;
> ::v-deep(i) { > ::v-deep(i) {
margin-right: 6px; margin-right: 6px;
transform: translateY(0.1em); transform: translateY(0.1em);
} }
&:empty { &:empty {
display: none; display: none;
} }
} }
> .sub { > .sub {
position: absolute; position: absolute;
z-index: 2; z-index: 2;
top: 0; top: 0;
right: 0; right: 0;
height: 100%; height: 100%;
> ::v-deep(button) { > ::v-deep(button) {
width: 42px; width: 42px;
height: 100%; height: 100%;
} }
} }
} }
> .content { > .content {
--stickyTop: 0px; --stickyTop: 0px;
&.omitted { &.omitted {
position: relative; position: relative;
max-height: var(--maxHeight); max-height: var(--maxHeight);
overflow: hidden; overflow: hidden;
> .fade { > .fade {
display: block; display: block;
position: absolute; position: absolute;
z-index: 10; z-index: 10;
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 64px; height: 64px;
background: linear-gradient(0deg, var(--panel), var(--X15)); background: linear-gradient(0deg, var(--panel), var(--X15));
> span { > span {
display: inline-block; display: inline-block;
background: var(--panel); background: var(--panel);
padding: 6px 10px; padding: 6px 10px;
font-size: 0.8em; font-size: 0.8em;
border-radius: 999px; border-radius: 999px;
box-shadow: 0 2px 6px rgb(0 0 0 / 20%); box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
} }
&:hover { &:hover {
> span { > span {
background: var(--panelHighlight); background: var(--panelHighlight);
} }
} }
} }
} }
} }
&.max-width_380px, &.max-width_380px,
&.thin { &.thin {
> header { > header {
> .title { > .title {
padding: 8px 10px; padding: 8px 10px;
font-size: 0.9em; font-size: 0.9em;
} }
} }
> .content { > .content {
} }
} }
} }
._forceContainerFull_ .ukygtjoj { ._forceContainerFull_ .ukygtjoj {
> header { > header {
> .title { > .title {
padding: 12px 16px !important; padding: 12px 16px !important;
} }
} }
} }
._forceContainerFull_.ukygtjoj { ._forceContainerFull_.ukygtjoj {
> header { > header {
> .title { > .title {
padding: 12px 16px !important; padding: 12px 16px !important;
} }
} }
} }
</style> </style>

Some files were not shown because too many files have changed in this diff Show More