Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55db9f9719 | ||
|
|
e3c3d1ac69 | ||
|
|
bd0279730c | ||
|
|
988f3a39f8 | ||
|
|
f65380f847 | ||
|
|
a62b7f0024 | ||
|
|
4512a1a91d | ||
|
|
af7d44164c | ||
|
|
6dbcb62da7 | ||
|
|
239de4c283 | ||
|
|
544236f1a0 | ||
|
|
145872b9f4 | ||
|
|
90c00b6db9 | ||
|
|
585003640f | ||
|
|
9440dc8dd5 | ||
|
|
9fe77baf05 | ||
|
|
133888d760 | ||
|
|
9160469a18 | ||
|
|
71ddb1f841 | ||
|
|
4f718cffbf | ||
|
|
b9d84fe007 | ||
|
|
ad970837ec | ||
|
|
d168128174 | ||
|
|
2919d4912c | ||
|
|
dcb9d75db7 |
@@ -95,7 +95,7 @@
|
||||
"nanoid": "^5.0.7",
|
||||
"nx": "^19.0.0",
|
||||
"nyc": "^17.0.0",
|
||||
"oxlint": "0.6.0",
|
||||
"oxlint": "0.6.1",
|
||||
"prettier": "^3.2.5",
|
||||
"semver": "^7.6.0",
|
||||
"serve": "^14.2.1",
|
||||
|
||||
@@ -8,16 +8,15 @@
|
||||
"run-test": "./scripts/run-test.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"run:script": "node --import ./scripts/register.js",
|
||||
"build": "tsc",
|
||||
"start": "yarn run:script ./src/index.ts",
|
||||
"start": "node --loader ts-node/esm/transpile-only.mjs ./src/index.ts",
|
||||
"dev": "nodemon ./src/index.ts",
|
||||
"test": "ava --concurrency 1 --serial",
|
||||
"test:coverage": "c8 ava --concurrency 1 --serial",
|
||||
"postinstall": "prisma generate",
|
||||
"data-migration": "yarn run:script ./src/data/index.ts",
|
||||
"predeploy": "yarn prisma migrate deploy && yarn run:script ./dist/data/index.js run",
|
||||
"db:upgrade": "yarn prisma migrate deploy && yarn data-migration run"
|
||||
"data-migration": "node --loader ts-node/esm/transpile-only.mjs ./src/data/index.ts",
|
||||
"predeploy": "yarn prisma migrate deploy && node --import ./scripts/register.js ./dist/data/index.js run",
|
||||
"predeploy:ts": "yarn prisma migrate deploy && node --loader ts-node/esm/transpile-only.mjs ./src/data/index.ts run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/server": "^4.10.2",
|
||||
@@ -43,8 +42,8 @@
|
||||
"@node-rs/jsonwebtoken": "^0.5.2",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/core": "^1.25.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-proto": "^0.52.0",
|
||||
"@opentelemetry/exporter-trace-otlp-proto": "^0.52.0",
|
||||
"@opentelemetry/exporter-prometheus": "^0.52.0",
|
||||
"@opentelemetry/exporter-zipkin": "^1.25.0",
|
||||
"@opentelemetry/host-metrics": "^0.35.2",
|
||||
"@opentelemetry/instrumentation": "^0.52.0",
|
||||
"@opentelemetry/instrumentation-graphql": "^0.42.0",
|
||||
@@ -166,8 +165,9 @@
|
||||
"exec": "node",
|
||||
"script": "./src/index.ts",
|
||||
"nodeArgs": [
|
||||
"--import",
|
||||
"./scripts/register.js"
|
||||
"--loader",
|
||||
"ts-node/esm.mjs",
|
||||
"--es-module-specifier-resolution=node"
|
||||
],
|
||||
"ignore": [
|
||||
"**/__tests__/**",
|
||||
|
||||
@@ -1,32 +1,11 @@
|
||||
import * as otel from '@opentelemetry/instrumentation/hook.mjs';
|
||||
import { createEsmHooks, register } from 'ts-node';
|
||||
import { create, createEsmHooks } from 'ts-node';
|
||||
|
||||
const service = register({
|
||||
const service = create({
|
||||
experimentalSpecifierResolution: 'node',
|
||||
transpileOnly: true,
|
||||
logError: true,
|
||||
skipProject: true,
|
||||
});
|
||||
const hooks = createEsmHooks(service);
|
||||
|
||||
/**
|
||||
* @type {import('ts-node').NodeLoaderHooksAPI2}
|
||||
|
||||
*/
|
||||
const ts = createEsmHooks(service);
|
||||
|
||||
/**
|
||||
* @type {import('ts-node').NodeLoaderHooksAPI2.ResolveHook}
|
||||
*/
|
||||
export const resolve = (specifier, context, defaultResolver) => {
|
||||
return ts.resolve(specifier, context, (s, c) => {
|
||||
return otel.resolve(s, c, defaultResolver);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {import('ts-node').NodeLoaderHooksAPI2.LoadHook}
|
||||
*/
|
||||
export const load = async (url, context, defaultLoader) => {
|
||||
return await otel.load(url, context, (u, c) => {
|
||||
return ts.load(u, c, defaultLoader);
|
||||
});
|
||||
};
|
||||
export const resolve = hooks.resolve;
|
||||
|
||||
@@ -3,13 +3,9 @@ import '../prelude';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { CommandFactory } from 'nest-commander';
|
||||
|
||||
import { registerInstrumentations } from '../fundamentals/metrics';
|
||||
|
||||
async function bootstrap() {
|
||||
AFFiNE.metrics.enabled = false;
|
||||
AFFiNE.doc.manager.enableUpdateAutoMerging = false;
|
||||
|
||||
registerInstrumentations();
|
||||
const { CliAppModule } = await import('./app');
|
||||
await CommandFactory.run(CliAppModule, new Logger()).catch(e => {
|
||||
console.error(e);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { PrismaClient, User } from '@prisma/client';
|
||||
|
||||
export class RefreshUnnamedUser1721299086340 {
|
||||
// do the migration
|
||||
static async up(db: PrismaClient) {
|
||||
await db.$transaction(async tx => {
|
||||
// only find users with unnamed names
|
||||
const users = await db.$queryRaw<
|
||||
User[]
|
||||
>`SELECT * FROM users WHERE name = 'Unnamed';`;
|
||||
|
||||
await Promise.all(
|
||||
users.map(({ id, email }) =>
|
||||
tx.user.update({
|
||||
where: { id },
|
||||
data: {
|
||||
name: email.split('@')[0],
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// revert the migration
|
||||
static async down(_db: PrismaClient) {}
|
||||
}
|
||||
@@ -50,7 +50,6 @@ export class MetricsModule implements OnModuleInit, OnModuleDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
export { registerInstrumentations } from './instrumentations';
|
||||
export * from './metrics';
|
||||
export * from './utils';
|
||||
export { OpentelemetryFactory };
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Instrumentation } from '@opentelemetry/instrumentation';
|
||||
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
|
||||
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
||||
import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';
|
||||
import { NestInstrumentation } from '@opentelemetry/instrumentation-nestjs-core';
|
||||
import { SocketIoInstrumentation } from '@opentelemetry/instrumentation-socket.io';
|
||||
import prismaInstrument from '@prisma/instrumentation';
|
||||
|
||||
const { PrismaInstrumentation } = prismaInstrument;
|
||||
|
||||
let instrumentations: Instrumentation[] = [];
|
||||
|
||||
export function registerInstrumentations(): void {
|
||||
if (AFFiNE.metrics.enabled) {
|
||||
instrumentations = [
|
||||
new NestInstrumentation(),
|
||||
new IORedisInstrumentation(),
|
||||
new SocketIoInstrumentation({ traceReserved: true }),
|
||||
new GraphQLInstrumentation({
|
||||
mergeItems: true,
|
||||
ignoreTrivialResolveSpans: true,
|
||||
depth: 10,
|
||||
}),
|
||||
new HttpInstrumentation(),
|
||||
new PrismaInstrumentation({ middleware: false }),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export function getRegisteredInstrumentations(): Instrumentation[] {
|
||||
return instrumentations;
|
||||
}
|
||||
@@ -1,82 +1,52 @@
|
||||
import { Attributes, metrics } from '@opentelemetry/api';
|
||||
import { OnModuleDestroy } from '@nestjs/common';
|
||||
import { metrics } from '@opentelemetry/api';
|
||||
import {
|
||||
CompositePropagator,
|
||||
W3CBaggagePropagator,
|
||||
W3CTraceContextPropagator,
|
||||
} from '@opentelemetry/core';
|
||||
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto';
|
||||
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
|
||||
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
|
||||
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
|
||||
import { HostMetrics } from '@opentelemetry/host-metrics';
|
||||
import { Instrumentation } from '@opentelemetry/instrumentation';
|
||||
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
|
||||
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
||||
import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';
|
||||
import { NestInstrumentation } from '@opentelemetry/instrumentation-nestjs-core';
|
||||
import { SocketIoInstrumentation } from '@opentelemetry/instrumentation-socket.io';
|
||||
import { Resource } from '@opentelemetry/resources';
|
||||
import type { MeterProvider } from '@opentelemetry/sdk-metrics';
|
||||
import {
|
||||
MetricProducer,
|
||||
MetricReader,
|
||||
PeriodicExportingMetricReader,
|
||||
} from '@opentelemetry/sdk-metrics';
|
||||
import { MetricProducer, MetricReader } from '@opentelemetry/sdk-metrics';
|
||||
import { NodeSDK } from '@opentelemetry/sdk-node';
|
||||
import {
|
||||
BatchSpanProcessor,
|
||||
SpanExporter,
|
||||
TraceIdRatioBasedSampler,
|
||||
} from '@opentelemetry/sdk-trace-node';
|
||||
import {
|
||||
SEMRESATTRS_K8S_CLUSTER_NAME,
|
||||
SEMRESATTRS_K8S_NAMESPACE_NAME,
|
||||
SEMRESATTRS_K8S_POD_NAME,
|
||||
SEMRESATTRS_SERVICE_NAME,
|
||||
SEMRESATTRS_SERVICE_VERSION,
|
||||
} from '@opentelemetry/semantic-conventions';
|
||||
import prismaInstrument from '@prisma/instrumentation';
|
||||
|
||||
import { getRegisteredInstrumentations } from './instrumentations';
|
||||
import { PrismaMetricProducer } from './prisma';
|
||||
|
||||
function withBuiltinAttributesMetricReader(
|
||||
reader: MetricReader,
|
||||
attrs: Attributes
|
||||
) {
|
||||
const collect = reader.collect;
|
||||
reader.collect = async options => {
|
||||
const result = await collect.call(reader, options);
|
||||
|
||||
result.resourceMetrics.scopeMetrics.forEach(metrics => {
|
||||
metrics.metrics.forEach(metric => {
|
||||
metric.dataPoints.forEach(dataPoint => {
|
||||
// @ts-expect-error allow
|
||||
dataPoint.attributes = Object.assign({}, attrs, dataPoint.attributes);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
function withBuiltinAttributesSpanExporter(
|
||||
exporter: SpanExporter,
|
||||
attrs: Attributes
|
||||
) {
|
||||
const exportSpans = exporter.export;
|
||||
exporter.export = (spans, callback) => {
|
||||
spans.forEach(span => {
|
||||
// patch span attributes
|
||||
// @ts-expect-error allow
|
||||
span.attributes = Object.assign({}, attrs, span.attributes);
|
||||
});
|
||||
|
||||
return exportSpans.call(exporter, spans, callback);
|
||||
};
|
||||
|
||||
return exporter;
|
||||
}
|
||||
const { PrismaInstrumentation } = prismaInstrument;
|
||||
|
||||
export abstract class OpentelemetryFactory {
|
||||
abstract getMetricReader(): MetricReader;
|
||||
abstract getSpanExporter(): SpanExporter;
|
||||
|
||||
getInstractions(): Instrumentation[] {
|
||||
return getRegisteredInstrumentations();
|
||||
return [
|
||||
new NestInstrumentation(),
|
||||
new IORedisInstrumentation(),
|
||||
new SocketIoInstrumentation({ traceReserved: true }),
|
||||
new GraphQLInstrumentation({ mergeItems: true }),
|
||||
new HttpInstrumentation(),
|
||||
new PrismaInstrumentation(),
|
||||
];
|
||||
}
|
||||
|
||||
getMetricsProducers(): MetricProducer[] {
|
||||
@@ -85,32 +55,20 @@ export abstract class OpentelemetryFactory {
|
||||
|
||||
getResource() {
|
||||
return new Resource({
|
||||
[SEMRESATTRS_K8S_CLUSTER_NAME]: AFFiNE.flavor.type,
|
||||
[SEMRESATTRS_K8S_NAMESPACE_NAME]: AFFiNE.AFFINE_ENV,
|
||||
[SEMRESATTRS_K8S_POD_NAME]: process.env.HOSTNAME ?? process.env.HOST,
|
||||
[SEMRESATTRS_SERVICE_NAME]: AFFiNE.flavor.type,
|
||||
[SEMRESATTRS_SERVICE_VERSION]: AFFiNE.version,
|
||||
});
|
||||
}
|
||||
|
||||
getBuiltinAttributes(): Attributes {
|
||||
return {
|
||||
[SEMRESATTRS_SERVICE_VERSION]: AFFiNE.version,
|
||||
};
|
||||
}
|
||||
|
||||
create() {
|
||||
const builtinAttributes = this.getBuiltinAttributes();
|
||||
|
||||
const traceExporter = this.getSpanExporter();
|
||||
return new NodeSDK({
|
||||
resource: this.getResource(),
|
||||
sampler: new TraceIdRatioBasedSampler(0.1),
|
||||
traceExporter: withBuiltinAttributesSpanExporter(
|
||||
this.getSpanExporter(),
|
||||
builtinAttributes
|
||||
),
|
||||
metricReader: withBuiltinAttributesMetricReader(
|
||||
this.getMetricReader(),
|
||||
builtinAttributes
|
||||
),
|
||||
traceExporter,
|
||||
metricReader: this.getMetricReader(),
|
||||
spanProcessor: new BatchSpanProcessor(traceExporter),
|
||||
textMapPropagator: new CompositePropagator({
|
||||
propagators: [
|
||||
new W3CBaggagePropagator(),
|
||||
@@ -123,19 +81,24 @@ export abstract class OpentelemetryFactory {
|
||||
}
|
||||
}
|
||||
|
||||
export class LocalOpentelemetryFactory extends OpentelemetryFactory {
|
||||
override getMetricReader() {
|
||||
return new PeriodicExportingMetricReader({
|
||||
// requires jeager service running in 'http://localhost:4318'
|
||||
// with metrics feature enabled.
|
||||
// see https://www.jaegertracing.io/docs/1.56/spm
|
||||
exporter: new OTLPMetricExporter(),
|
||||
});
|
||||
export class LocalOpentelemetryFactory
|
||||
extends OpentelemetryFactory
|
||||
implements OnModuleDestroy
|
||||
{
|
||||
private readonly metricsExporter = new PrometheusExporter({
|
||||
metricProducers: this.getMetricsProducers(),
|
||||
});
|
||||
|
||||
async onModuleDestroy() {
|
||||
await this.metricsExporter.shutdown();
|
||||
}
|
||||
|
||||
override getSpanExporter() {
|
||||
// requires jeager service running in 'http://localhost:4318'
|
||||
return new OTLPTraceExporter();
|
||||
override getMetricReader(): MetricReader {
|
||||
return this.metricsExporter;
|
||||
}
|
||||
|
||||
override getSpanExporter(): SpanExporter {
|
||||
return new ZipkinExporter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@ import { omit } from 'lodash-es';
|
||||
|
||||
import { createApp } from './app';
|
||||
import { URLHelper } from './fundamentals';
|
||||
import { registerInstrumentations } from './fundamentals/metrics';
|
||||
|
||||
registerInstrumentations();
|
||||
const app = await createApp();
|
||||
const listeningHost = AFFiNE.deploy ? '0.0.0.0' : 'localhost';
|
||||
await app.listen(AFFiNE.server.port, listeningHost);
|
||||
|
||||
@@ -108,17 +108,33 @@ class CreateChatMessageInput implements Omit<SubmittedMessage, 'content'> {
|
||||
params!: Record<string, string> | undefined;
|
||||
}
|
||||
|
||||
enum ChatHistoryOrder {
|
||||
asc = 'asc',
|
||||
desc = 'desc',
|
||||
}
|
||||
|
||||
registerEnumType(ChatHistoryOrder, { name: 'ChatHistoryOrder' });
|
||||
|
||||
@InputType()
|
||||
class QueryChatHistoriesInput implements Partial<ListHistoriesOptions> {
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
action: boolean | undefined;
|
||||
|
||||
@Field(() => Boolean, { nullable: true })
|
||||
fork: boolean | undefined;
|
||||
|
||||
@Field(() => Number, { nullable: true })
|
||||
limit: number | undefined;
|
||||
|
||||
@Field(() => Number, { nullable: true })
|
||||
skip: number | undefined;
|
||||
|
||||
@Field(() => ChatHistoryOrder, { nullable: true })
|
||||
messageOrder: 'asc' | 'desc' | undefined;
|
||||
|
||||
@Field(() => ChatHistoryOrder, { nullable: true })
|
||||
sessionOrder: 'asc' | 'desc' | undefined;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
sessionId: string | undefined;
|
||||
}
|
||||
|
||||
@@ -382,6 +382,21 @@ export class ChatSessionService {
|
||||
options?: ListHistoriesOptions,
|
||||
withPrompt = false
|
||||
): Promise<ChatHistory[]> {
|
||||
const extraCondition = [];
|
||||
|
||||
if (!options?.action && options?.fork) {
|
||||
// only query forked session if fork == true and action == false
|
||||
extraCondition.push({
|
||||
userId: { not: userId },
|
||||
workspaceId: workspaceId,
|
||||
docId: workspaceId === docId ? undefined : docId,
|
||||
id: options?.sessionId ? { equals: options.sessionId } : undefined,
|
||||
// should only find forked session
|
||||
parentSessionId: { not: null },
|
||||
deletedAt: null,
|
||||
});
|
||||
}
|
||||
|
||||
return await this.db.aiSession
|
||||
.findMany({
|
||||
where: {
|
||||
@@ -395,21 +410,7 @@ export class ChatSessionService {
|
||||
: undefined,
|
||||
deletedAt: null,
|
||||
},
|
||||
...(options?.action
|
||||
? []
|
||||
: [
|
||||
{
|
||||
userId: { not: userId },
|
||||
workspaceId: workspaceId,
|
||||
docId: workspaceId === docId ? undefined : docId,
|
||||
id: options?.sessionId
|
||||
? { equals: options.sessionId }
|
||||
: undefined,
|
||||
// should only find forked session
|
||||
parentSessionId: { not: null },
|
||||
deletedAt: null,
|
||||
},
|
||||
]),
|
||||
...extraCondition,
|
||||
],
|
||||
},
|
||||
select: {
|
||||
@@ -428,13 +429,17 @@ export class ChatSessionService {
|
||||
createdAt: true,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc',
|
||||
// message order is asc by default
|
||||
createdAt: options?.messageOrder === 'desc' ? 'desc' : 'asc',
|
||||
},
|
||||
},
|
||||
},
|
||||
take: options?.limit,
|
||||
skip: options?.skip,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
orderBy: {
|
||||
// session order is desc by default
|
||||
createdAt: options?.sessionOrder === 'asc' ? 'asc' : 'desc',
|
||||
},
|
||||
})
|
||||
.then(sessions =>
|
||||
Promise.all(
|
||||
|
||||
@@ -131,8 +131,11 @@ export interface ChatSessionState
|
||||
|
||||
export type ListHistoriesOptions = {
|
||||
action: boolean | undefined;
|
||||
fork: boolean | undefined;
|
||||
limit: number | undefined;
|
||||
skip: number | undefined;
|
||||
sessionOrder: 'asc' | 'desc' | undefined;
|
||||
messageOrder: 'asc' | 'desc' | undefined;
|
||||
sessionId: string | undefined;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@ type BlobNotFoundDataType {
|
||||
workspaceId: String!
|
||||
}
|
||||
|
||||
enum ChatHistoryOrder {
|
||||
asc
|
||||
desc
|
||||
}
|
||||
|
||||
type ChatMessage {
|
||||
attachments: [String!]
|
||||
content: String!
|
||||
@@ -554,8 +559,11 @@ type Query {
|
||||
|
||||
input QueryChatHistoriesInput {
|
||||
action: Boolean
|
||||
fork: Boolean
|
||||
limit: Int
|
||||
messageOrder: ChatHistoryOrder
|
||||
sessionId: String
|
||||
sessionOrder: ChatHistoryOrder
|
||||
skip: Int
|
||||
}
|
||||
|
||||
|
||||
@@ -564,15 +564,29 @@ test('should be able to list history', async t => {
|
||||
promptName
|
||||
);
|
||||
|
||||
const messageId = await createCopilotMessage(app, token, sessionId);
|
||||
const messageId = await createCopilotMessage(app, token, sessionId, 'hello');
|
||||
await chatWithText(app, token, sessionId, messageId);
|
||||
|
||||
const histories = await getHistories(app, token, { workspaceId });
|
||||
t.deepEqual(
|
||||
histories.map(h => h.messages.map(m => m.content)),
|
||||
[['generate text to text']],
|
||||
'should be able to list history'
|
||||
);
|
||||
{
|
||||
const histories = await getHistories(app, token, { workspaceId });
|
||||
t.deepEqual(
|
||||
histories.map(h => h.messages.map(m => m.content)),
|
||||
[['hello', 'generate text to text']],
|
||||
'should be able to list history'
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
const histories = await getHistories(app, token, {
|
||||
workspaceId,
|
||||
options: { messageOrder: 'desc' },
|
||||
});
|
||||
t.deepEqual(
|
||||
histories.map(h => h.messages.map(m => m.content)),
|
||||
[['generate text to text', 'hello']],
|
||||
'should be able to list history'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('should reject request that user have not permission', async t => {
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
WorkflowParams,
|
||||
} from '../../src/plugins/copilot/workflow/types';
|
||||
import { gql } from './common';
|
||||
import { handleGraphQLError } from './utils';
|
||||
import { handleGraphQLError, sleep } from './utils';
|
||||
|
||||
// @ts-expect-error no error
|
||||
export class MockCopilotTestProvider
|
||||
@@ -84,6 +84,8 @@ export class MockCopilotTestProvider
|
||||
options: CopilotChatOptions = {}
|
||||
): Promise<string> {
|
||||
this.checkParams({ messages, model, options });
|
||||
// make some time gap for history test case
|
||||
await sleep(100);
|
||||
return 'generate text to text';
|
||||
}
|
||||
|
||||
@@ -94,6 +96,8 @@ export class MockCopilotTestProvider
|
||||
): AsyncIterable<string> {
|
||||
this.checkParams({ messages, model, options });
|
||||
|
||||
// make some time gap for history test case
|
||||
await sleep(100);
|
||||
const result = 'generate text to text stream';
|
||||
for await (const message of result) {
|
||||
yield message;
|
||||
@@ -113,6 +117,8 @@ export class MockCopilotTestProvider
|
||||
messages = Array.isArray(messages) ? messages : [messages];
|
||||
this.checkParams({ embeddings: messages, model, options });
|
||||
|
||||
// make some time gap for history test case
|
||||
await sleep(100);
|
||||
return [Array.from(randomBytes(options.dimensions)).map(v => v % 128)];
|
||||
}
|
||||
|
||||
@@ -130,6 +136,8 @@ export class MockCopilotTestProvider
|
||||
throw new Error('Prompt is required');
|
||||
}
|
||||
|
||||
// make some time gap for history test case
|
||||
await sleep(100);
|
||||
// just let test case can easily verify the final prompt
|
||||
return [`https://example.com/${model}.jpg`, prompt];
|
||||
}
|
||||
@@ -338,10 +346,13 @@ export async function getHistories(
|
||||
workspaceId: string;
|
||||
docId?: string;
|
||||
options?: {
|
||||
sessionId?: string;
|
||||
action?: boolean;
|
||||
fork?: boolean;
|
||||
limit?: number;
|
||||
skip?: number;
|
||||
sessionOrder?: 'asc' | 'desc';
|
||||
messageOrder?: 'asc' | 'desc';
|
||||
sessionId?: string;
|
||||
};
|
||||
}
|
||||
): Promise<History[]> {
|
||||
|
||||
@@ -149,7 +149,6 @@ export async function changePassword(
|
||||
variables: { token, password },
|
||||
})
|
||||
.expect(200);
|
||||
console.log(JSON.stringify(res.body));
|
||||
return res.body.data.changePassword.id;
|
||||
}
|
||||
|
||||
|
||||
@@ -167,3 +167,7 @@ export function gql(app: INestApplication, query?: string) {
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
export async function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
4
packages/common/env/package.json
vendored
@@ -3,8 +3,8 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@blocksuite/global": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/store": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/global": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/store": "0.16.0-canary-202407200848-42035fe",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"vitest": "1.6.0"
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
"@affine/debug": "workspace:*",
|
||||
"@affine/env": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"@blocksuite/blocks": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/global": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/store": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/blocks": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/global": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/store": "0.16.0-canary-202407200848-42035fe",
|
||||
"@datastructures-js/binary-search-tree": "^5.3.2",
|
||||
"foxact": "^0.2.33",
|
||||
"fuse.js": "^7.0.0",
|
||||
@@ -33,8 +33,8 @@
|
||||
"devDependencies": {
|
||||
"@affine-test/fixtures": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"@blocksuite/block-std": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/presets": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/block-std": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/presets": "0.16.0-canary-202407200848-42035fe",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
"async-call-rpc": "^6.4.0",
|
||||
"fake-indexeddb": "^6.0.0",
|
||||
|
||||
@@ -26,6 +26,7 @@ const TEST_SCHEMA = {
|
||||
users: {
|
||||
id: f.number().primaryKey().default(incremental()),
|
||||
name: f.string(),
|
||||
email: f.string().optional(),
|
||||
},
|
||||
} satisfies DBSchemaBuilder;
|
||||
|
||||
@@ -211,9 +212,11 @@ describe('ORM entity CRUD', () => {
|
||||
test('should be able to subscribe to entity key list', t => {
|
||||
const { client } = t;
|
||||
|
||||
let callbackCount = 0;
|
||||
let keys: string[] = [];
|
||||
const subscription = client.tags.keys$().subscribe(data => {
|
||||
keys = data;
|
||||
callbackCount++;
|
||||
});
|
||||
|
||||
client.tags.create({
|
||||
@@ -229,6 +232,7 @@ describe('ORM entity CRUD', () => {
|
||||
|
||||
client.tags.delete('test');
|
||||
expect(keys).toStrictEqual([]);
|
||||
expect(callbackCount).toStrictEqual(3); // init, create, delete
|
||||
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
@@ -236,9 +240,11 @@ describe('ORM entity CRUD', () => {
|
||||
test('should be able to subscribe to filtered entity changes', t => {
|
||||
const { client } = t;
|
||||
|
||||
let callbackCount = 0;
|
||||
let entities: any[] = [];
|
||||
const subscription = client.tags.find$({ name: 'test' }).subscribe(data => {
|
||||
entities = data;
|
||||
callbackCount++;
|
||||
});
|
||||
|
||||
const tag1 = client.tags.create({
|
||||
@@ -257,6 +263,24 @@ describe('ORM entity CRUD', () => {
|
||||
|
||||
expect(entities).toStrictEqual([tag1, tag2]);
|
||||
|
||||
client.tags.create({
|
||||
id: '3',
|
||||
name: 'not-test',
|
||||
color: 'yellow',
|
||||
});
|
||||
|
||||
expect(entities).toStrictEqual([tag1, tag2]);
|
||||
expect(callbackCount).toStrictEqual(3);
|
||||
|
||||
client.tags.update('1', { color: 'green' });
|
||||
expect(entities).toStrictEqual([{ ...tag1, color: 'green' }, tag2]);
|
||||
|
||||
client.tags.delete('1');
|
||||
expect(entities).toStrictEqual([tag2]);
|
||||
|
||||
client.tags.delete('2');
|
||||
expect(entities).toStrictEqual([]);
|
||||
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
@@ -264,7 +288,7 @@ describe('ORM entity CRUD', () => {
|
||||
const { client } = t;
|
||||
|
||||
let entities: any[] = [];
|
||||
const subscription = client.tags.find$({}).subscribe(data => {
|
||||
const subscription = client.tags.find$().subscribe(data => {
|
||||
entities = data;
|
||||
});
|
||||
|
||||
@@ -302,4 +326,82 @@ describe('ORM entity CRUD', () => {
|
||||
"[Table(tags)]: Field '$$DELETED' is reserved keyword and can't be used"
|
||||
);
|
||||
});
|
||||
|
||||
test('should be able to validate entity data', t => {
|
||||
const { client } = t;
|
||||
|
||||
expect(() => {
|
||||
client.users.create({
|
||||
// @ts-expect-error
|
||||
name: null,
|
||||
});
|
||||
}).toThrowError("Field 'name' is required but not set.");
|
||||
|
||||
expect(() => {
|
||||
// @ts-expect-error
|
||||
client.users.create({});
|
||||
}).toThrowError("Field 'name' is required but not set.");
|
||||
|
||||
expect(() => {
|
||||
client.users.update(1, {
|
||||
// @ts-expect-error
|
||||
name: null,
|
||||
});
|
||||
}).toThrowError("Field 'name' is required but not set.");
|
||||
});
|
||||
|
||||
test('should be able to set optional field to null', t => {
|
||||
const { client } = t;
|
||||
|
||||
{
|
||||
const user = client.users.create({
|
||||
name: 'test',
|
||||
});
|
||||
|
||||
expect(user.email).toBe(null);
|
||||
}
|
||||
|
||||
{
|
||||
const user = client.users.create({
|
||||
name: 'test',
|
||||
email: null,
|
||||
});
|
||||
|
||||
expect(user.email).toBe(null);
|
||||
}
|
||||
|
||||
{
|
||||
const user = client.users.create({
|
||||
name: 'test',
|
||||
email: 'test@example.com',
|
||||
});
|
||||
|
||||
client.users.update(user.id, {
|
||||
email: null,
|
||||
});
|
||||
|
||||
expect(client.users.get(user.id)!.email).toBe(null);
|
||||
}
|
||||
});
|
||||
|
||||
test('should be able to find entity by optional field', t => {
|
||||
const { client } = t;
|
||||
|
||||
const user = client.users.create({
|
||||
name: 'test',
|
||||
email: null,
|
||||
});
|
||||
|
||||
{
|
||||
const found = client.users.find({ email: null });
|
||||
|
||||
expect(found).toEqual([user]);
|
||||
}
|
||||
|
||||
{
|
||||
const found = client.users.find({ email: undefined });
|
||||
|
||||
expect(found).toEqual([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,36 +104,47 @@ export class YjsTableAdapter implements TableAdapter {
|
||||
const { where, select, callback } = query;
|
||||
|
||||
let listeningOnAll = false;
|
||||
const obKeys = new Set<any>();
|
||||
const results = [];
|
||||
const results = new Map<string, any>();
|
||||
|
||||
if (!where) {
|
||||
listeningOnAll = true;
|
||||
} else if ('byKey' in where) {
|
||||
obKeys.add(where.byKey.toString());
|
||||
}
|
||||
|
||||
for (const record of this.iterate(where)) {
|
||||
if (!listeningOnAll) {
|
||||
obKeys.add(this.keyof(record));
|
||||
}
|
||||
results.push(this.value(record, select));
|
||||
results.set(this.keyof(record), this.value(record, select));
|
||||
}
|
||||
|
||||
callback(results);
|
||||
callback(Array.from(results.values()));
|
||||
|
||||
const ob = (tx: Transaction) => {
|
||||
let hasChanged = false;
|
||||
for (const [ty] of tx.changed) {
|
||||
const record = ty as unknown as AbstractType<any>;
|
||||
if (
|
||||
listeningOnAll ||
|
||||
obKeys.has(this.keyof(record)) ||
|
||||
(where && this.match(record, where))
|
||||
) {
|
||||
callback(this.find({ where, select }));
|
||||
return;
|
||||
const record = ty;
|
||||
const key = this.keyof(record);
|
||||
const isMatch =
|
||||
(listeningOnAll || (where && this.match(record, where))) &&
|
||||
!this.isDeleted(record);
|
||||
const prevMatch = results.get(key);
|
||||
const isPrevMatched = results.has(key);
|
||||
|
||||
if (isMatch && isPrevMatched) {
|
||||
const newValue = this.value(record, select);
|
||||
if (prevMatch !== newValue) {
|
||||
results.set(key, newValue);
|
||||
hasChanged = true;
|
||||
}
|
||||
} else if (isMatch && !isPrevMatched) {
|
||||
results.set(this.keyof(record), this.value(record, select));
|
||||
hasChanged = true;
|
||||
} else if (!isMatch && isPrevMatched) {
|
||||
results.delete(key);
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChanged) {
|
||||
callback(Array.from(results.values()));
|
||||
}
|
||||
};
|
||||
|
||||
this.doc.on('afterTransaction', ob);
|
||||
@@ -165,9 +176,16 @@ export class YjsTableAdapter implements TableAdapter {
|
||||
return null;
|
||||
}
|
||||
|
||||
private *iterate(where: WhereCondition = []) {
|
||||
private *iterate(where?: WhereCondition) {
|
||||
if (!where) {
|
||||
for (const map of this.doc.share.values()) {
|
||||
if (!this.isDeleted(map)) {
|
||||
yield map;
|
||||
}
|
||||
}
|
||||
}
|
||||
// fast pass for key lookup without iterating the whole table
|
||||
if ('byKey' in where) {
|
||||
else if ('byKey' in where) {
|
||||
const record = this.recordByKey(where.byKey.toString());
|
||||
if (record) {
|
||||
yield record;
|
||||
@@ -202,7 +220,9 @@ export class YjsTableAdapter implements TableAdapter {
|
||||
return (
|
||||
!this.isDeleted(record) &&
|
||||
(Array.isArray(where)
|
||||
? where.every(c => this.field(record, c.field) === c.value)
|
||||
? where.length === 0
|
||||
? false
|
||||
: where.every(c => this.field(record, c.field) === c.value)
|
||||
: where.byKey === this.keyof(record))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,9 @@ type OptionalFields<T extends TableSchemaBuilder> = {
|
||||
? Optional extends true
|
||||
? K
|
||||
: never
|
||||
: never]?: T[K] extends FieldSchemaBuilder<infer Type> ? Type : never;
|
||||
: never]?: T[K] extends FieldSchemaBuilder<infer Type>
|
||||
? Type | null
|
||||
: never;
|
||||
};
|
||||
|
||||
type PrimaryKeyField<T extends TableSchemaBuilder> = {
|
||||
@@ -68,17 +70,13 @@ export type Entity<T extends TableSchemaBuilder> = Pretty<
|
||||
>;
|
||||
|
||||
export type UpdateEntityInput<T extends TableSchemaBuilder> = Pretty<{
|
||||
[key in NonPrimaryKeyFields<T>]?: T[key] extends FieldSchemaBuilder<
|
||||
infer Type
|
||||
>
|
||||
? Type
|
||||
[key in NonPrimaryKeyFields<T>]?: key extends keyof Entity<T>
|
||||
? Entity<T>[key]
|
||||
: never;
|
||||
}>;
|
||||
|
||||
export type FindEntityInput<T extends TableSchemaBuilder> = Pretty<{
|
||||
[key in keyof T]?: T[key] extends FieldSchemaBuilder<infer Type>
|
||||
? Type
|
||||
: never;
|
||||
[key in keyof T]?: key extends keyof Entity<T> ? Entity<T>[key] : never;
|
||||
}>;
|
||||
|
||||
export class Table<T extends TableSchemaBuilder> {
|
||||
@@ -192,22 +190,30 @@ export class Table<T extends TableSchemaBuilder> {
|
||||
return ob$;
|
||||
}
|
||||
|
||||
find(where: FindEntityInput<T>): Entity<T>[] {
|
||||
find(where?: FindEntityInput<T>): Entity<T>[] {
|
||||
return this.adapter.find({
|
||||
where: Object.entries(where).map(([field, value]) => ({
|
||||
field,
|
||||
value,
|
||||
})),
|
||||
where: !where
|
||||
? undefined
|
||||
: Object.entries(where)
|
||||
.map(([field, value]) => ({
|
||||
field,
|
||||
value,
|
||||
}))
|
||||
.filter(({ value }) => value !== undefined),
|
||||
});
|
||||
}
|
||||
|
||||
find$(where: FindEntityInput<T>): Observable<Entity<T>[]> {
|
||||
find$(where?: FindEntityInput<T>): Observable<Entity<T>[]> {
|
||||
return new Observable<Entity<T>[]>(subscriber => {
|
||||
const unsubscribe = this.adapter.observe({
|
||||
where: Object.entries(where).map(([field, value]) => ({
|
||||
field,
|
||||
value,
|
||||
})),
|
||||
where: !where
|
||||
? undefined
|
||||
: Object.entries(where)
|
||||
.map(([field, value]) => ({
|
||||
field,
|
||||
value,
|
||||
}))
|
||||
.filter(({ value }) => value !== undefined),
|
||||
callback: data => {
|
||||
subscriber.next(data);
|
||||
},
|
||||
|
||||
@@ -65,14 +65,13 @@ export const dataValidators = {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
val === null &&
|
||||
(!field.optional ||
|
||||
field.optional) /* say 'null' can be stored as 'json' */
|
||||
) {
|
||||
throw new Error(
|
||||
`[Table(${table.name})]: Field '${key}' is required but set as null.`
|
||||
);
|
||||
if (val === null) {
|
||||
if (!field.optional) {
|
||||
throw new Error(
|
||||
`[Table(${table.name})]: Field '${key}' is required but not set.`
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const typeGet = inputType(val);
|
||||
@@ -97,10 +96,13 @@ export const dataValidators = {
|
||||
|
||||
const val = data[key];
|
||||
|
||||
if ((val === undefined || val === null) && !field.optional) {
|
||||
throw new Error(
|
||||
`[Table(${table.name})]: Field '${key}' is required but not set.`
|
||||
);
|
||||
if (val === undefined || val === null) {
|
||||
if (!field.optional) {
|
||||
throw new Error(
|
||||
`[Table(${table.name})]: Field '${key}' is required but not set.`
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const typeGet = inputType(val);
|
||||
|
||||
@@ -78,12 +78,12 @@
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blocksuite/block-std": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/blocks": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/global": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/icons": "2.1.58",
|
||||
"@blocksuite/presets": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/store": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/block-std": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/blocks": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/global": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/icons": "2.1.59",
|
||||
"@blocksuite/presets": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/store": "0.16.0-canary-202407200848-42035fe",
|
||||
"@storybook/addon-actions": "^7.6.17",
|
||||
"@storybook/addon-essentials": "^7.6.17",
|
||||
"@storybook/addon-interactions": "^7.6.17",
|
||||
|
||||
@@ -10,7 +10,8 @@ import * as VisuallyHidden from '@radix-ui/react-visually-hidden';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { forwardRef, useCallback } from 'react';
|
||||
import { forwardRef, useCallback, useEffect } from 'react';
|
||||
import { type TransitionState, useTransition } from 'react-transition-state';
|
||||
|
||||
import type { IconButtonProps } from '../button';
|
||||
import { IconButton } from '../button';
|
||||
@@ -28,7 +29,8 @@ export interface ModalProps extends DialogProps {
|
||||
* @default false
|
||||
*/
|
||||
persistent?: boolean;
|
||||
|
||||
// animation for modal open/close
|
||||
animationTimeout?: number;
|
||||
portalOptions?: DialogPortalProps;
|
||||
contentOptions?: DialogContentProps;
|
||||
overlayOptions?: DialogOverlayProps;
|
||||
@@ -57,8 +59,10 @@ export const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
||||
withoutCloseButton = false,
|
||||
modal,
|
||||
persistent,
|
||||
|
||||
animationTimeout = 120,
|
||||
portalOptions,
|
||||
open: customOpen,
|
||||
onOpenChange: customOnOpenChange,
|
||||
contentOptions: {
|
||||
style: contentStyle,
|
||||
className: contentClassName,
|
||||
@@ -68,6 +72,7 @@ export const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
||||
} = {},
|
||||
overlayOptions: {
|
||||
className: overlayClassName,
|
||||
style: overlayStyle,
|
||||
...otherOverlayOptions
|
||||
} = {},
|
||||
closeButtonOptions = {},
|
||||
@@ -76,11 +81,38 @@ export const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [{ status }, toggle] = useTransition({
|
||||
timeout: animationTimeout,
|
||||
onStateChange: useCallback(
|
||||
({ current }: { current: TransitionState }) => {
|
||||
// add more status if needed
|
||||
if (current.status === 'exited') customOnOpenChange?.(false);
|
||||
if (current.status === 'entered') customOnOpenChange?.(true);
|
||||
},
|
||||
[customOnOpenChange]
|
||||
),
|
||||
});
|
||||
useEffect(() => {
|
||||
toggle(customOpen);
|
||||
}, [customOpen]);
|
||||
|
||||
return (
|
||||
<Dialog.Root modal={modal} {...props}>
|
||||
<Dialog.Root
|
||||
modal={modal}
|
||||
open={status !== 'exited'}
|
||||
onOpenChange={toggle}
|
||||
{...props}
|
||||
>
|
||||
<Dialog.Portal {...portalOptions}>
|
||||
<Dialog.Overlay
|
||||
className={clsx(styles.modalOverlay, overlayClassName)}
|
||||
data-state={status}
|
||||
style={{
|
||||
...assignInlineVars({
|
||||
[styles.animationTimeout]: `${animationTimeout}ms`,
|
||||
}),
|
||||
...overlayStyle,
|
||||
}}
|
||||
{...otherOverlayOptions}
|
||||
/>
|
||||
<div data-modal={modal} className={clsx(styles.modalContentWrapper)}>
|
||||
@@ -100,14 +132,17 @@ export const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
||||
[onEscapeKeyDown, persistent]
|
||||
)}
|
||||
className={clsx(styles.modalContent, contentClassName)}
|
||||
data-state={status}
|
||||
style={{
|
||||
...assignInlineVars({
|
||||
[styles.widthVar]: getVar(width, '50vw'),
|
||||
[styles.heightVar]: getVar(height, 'unset'),
|
||||
[styles.minHeightVar]: getVar(minHeight, '26px'),
|
||||
[styles.animationTimeout]: `${animationTimeout}ms`,
|
||||
}),
|
||||
...contentStyle,
|
||||
}}
|
||||
{...(description ? {} : { 'aria-describedby': undefined })}
|
||||
{...otherContentOptions}
|
||||
ref={ref}
|
||||
>
|
||||
|
||||
@@ -1,13 +1,61 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { createVar, globalStyle, style } from '@vanilla-extract/css';
|
||||
import { createVar, globalStyle, keyframes, style } from '@vanilla-extract/css';
|
||||
export const widthVar = createVar('widthVar');
|
||||
export const heightVar = createVar('heightVar');
|
||||
export const minHeightVar = createVar('minHeightVar');
|
||||
export const animationTimeout = createVar();
|
||||
|
||||
const overlayShow = keyframes({
|
||||
from: {
|
||||
opacity: 0,
|
||||
},
|
||||
to: {
|
||||
opacity: 1,
|
||||
},
|
||||
});
|
||||
const overlayHide = keyframes({
|
||||
to: {
|
||||
opacity: 0,
|
||||
},
|
||||
from: {
|
||||
opacity: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const contentShow = keyframes({
|
||||
from: {
|
||||
opacity: 0,
|
||||
transform: 'translateY(-2%) scale(0.96)',
|
||||
},
|
||||
to: {
|
||||
opacity: 1,
|
||||
transform: 'translateY(0) scale(1)',
|
||||
},
|
||||
});
|
||||
const contentHide = keyframes({
|
||||
to: {
|
||||
opacity: 0,
|
||||
transform: 'translateY(-2%) scale(0.96)',
|
||||
},
|
||||
from: {
|
||||
opacity: 1,
|
||||
transform: 'translateY(0) scale(1)',
|
||||
},
|
||||
});
|
||||
|
||||
export const modalOverlay = style({
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
backgroundColor: cssVar('backgroundModalColor'),
|
||||
zIndex: cssVar('zIndexModal'),
|
||||
selectors: {
|
||||
'&[data-state=entered], &[data-state=entering]': {
|
||||
animation: `${overlayShow} ${animationTimeout} forwards`,
|
||||
},
|
||||
'&[data-state=exited], &[data-state=exiting]': {
|
||||
animation: `${overlayHide} ${animationTimeout} forwards`,
|
||||
},
|
||||
},
|
||||
});
|
||||
export const modalContentWrapper = style({
|
||||
position: 'fixed',
|
||||
@@ -39,6 +87,16 @@ export const modalContent = style({
|
||||
maxHeight: 'calc(100vh - 32px)',
|
||||
// :focus-visible will set outline
|
||||
outline: 'none',
|
||||
selectors: {
|
||||
'&[data-state=entered], &[data-state=entering]': {
|
||||
animation: `${contentShow} ${animationTimeout} cubic-bezier(0.42, 0, 0.58, 1)`,
|
||||
animationFillMode: 'forwards',
|
||||
},
|
||||
'&[data-state=exited], &[data-state=exiting]': {
|
||||
animation: `${contentHide} ${animationTimeout} cubic-bezier(0.42, 0, 0.58, 1)`,
|
||||
animationFillMode: 'forwards',
|
||||
},
|
||||
},
|
||||
});
|
||||
export const closeButton = style({
|
||||
position: 'absolute',
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
"@affine/graphql": "workspace:*",
|
||||
"@affine/i18n": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"@blocksuite/block-std": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/blocks": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/global": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/icons": "2.1.58",
|
||||
"@blocksuite/inline": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/presets": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/store": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/block-std": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/blocks": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/global": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/icons": "2.1.59",
|
||||
"@blocksuite/inline": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/presets": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/store": "0.16.0-canary-202407200848-42035fe",
|
||||
"@dnd-kit/core": "^6.1.0",
|
||||
"@dnd-kit/modifiers": "^7.0.0",
|
||||
"@dnd-kit/sortable": "^8.0.0",
|
||||
|
||||
@@ -10,6 +10,9 @@ export async function getMarkdownFromSlice(host: EditorHost, slice: Slice) {
|
||||
});
|
||||
const markdownAdapter = new MarkdownAdapter(job);
|
||||
const markdown = await markdownAdapter.fromSlice(slice);
|
||||
if (!markdown) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return markdown.file;
|
||||
}
|
||||
@@ -63,7 +66,9 @@ export async function insertFromMarkdown(
|
||||
parent,
|
||||
(index ?? 0) + i
|
||||
);
|
||||
models.push(model);
|
||||
if (model) {
|
||||
models.push(model);
|
||||
}
|
||||
}
|
||||
|
||||
return models;
|
||||
|
||||
@@ -438,7 +438,6 @@ export function actionToHandler<T extends keyof BlockSuitePresets.AIActions>(
|
||||
edgelessCopilot.hideCopilotPanel();
|
||||
edgelessCopilot.lockToolbar(true);
|
||||
|
||||
aiPanel.host = host;
|
||||
updateEdgelessAIPanelConfig(
|
||||
aiPanel,
|
||||
edgelessCopilot,
|
||||
|
||||
@@ -210,7 +210,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
||||
display: 'flex',
|
||||
height: '28px',
|
||||
gap: '8px',
|
||||
width: '85%',
|
||||
width: '88%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'start',
|
||||
cursor: 'pointer',
|
||||
|
||||
@@ -80,6 +80,9 @@ export async function getContentFromSlice(
|
||||
middlewares: [titleMiddleware, embedSyncedDocMiddleware('content')],
|
||||
});
|
||||
const snapshot = await job.sliceToSnapshot(slice);
|
||||
if (!snapshot) {
|
||||
return '';
|
||||
}
|
||||
processTextInSnapshot(snapshot, host);
|
||||
const adapter =
|
||||
type === 'markdown' ? new MarkdownAdapter(job) : new PlainTextAdapter(job);
|
||||
@@ -96,6 +99,9 @@ export async function getPlainTextFromSlice(host: EditorHost, slice: Slice) {
|
||||
middlewares: [titleMiddleware],
|
||||
});
|
||||
const snapshot = await job.sliceToSnapshot(slice);
|
||||
if (!snapshot) {
|
||||
return '';
|
||||
}
|
||||
processTextInSnapshot(snapshot, host);
|
||||
const plainTextAdapter = new PlainTextAdapter(job);
|
||||
const plainText = await plainTextAdapter.fromSliceSnapshot({
|
||||
@@ -158,7 +164,9 @@ export async function insertFromMarkdown(
|
||||
parent,
|
||||
(index ?? 0) + i
|
||||
);
|
||||
models.push(model);
|
||||
if (model) {
|
||||
models.push(model);
|
||||
}
|
||||
}
|
||||
|
||||
return models;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { notify } from '@affine/component';
|
||||
import { AuthInput, ModalHeader } from '@affine/component/auth-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { authAtom } from '@affine/core/atoms';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import { ArrowDownBigIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
@@ -34,6 +36,7 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
const [verifyToken, challenge] = useCaptcha();
|
||||
|
||||
const [isValidEmail, setIsValidEmail] = useState(true);
|
||||
const { openModal } = useAtomValue(authAtom);
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setInterval(() => {
|
||||
@@ -45,7 +48,7 @@ export const SignIn: FC<AuthPanelProps> = ({
|
||||
};
|
||||
}, [authService]);
|
||||
const loginStatus = useLiveData(authService.session.status$);
|
||||
if (loginStatus === 'authenticated') {
|
||||
if (loginStatus === 'authenticated' && openModal) {
|
||||
onSignedIn?.();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,3 +37,9 @@ export const scrollBar = style({
|
||||
width: 6,
|
||||
transform: 'translateX(-4px)',
|
||||
});
|
||||
|
||||
export const hiddenInput = style({
|
||||
width: '0',
|
||||
height: '0',
|
||||
position: 'absolute',
|
||||
});
|
||||
|
||||
@@ -39,7 +39,9 @@ export const InfoModal = ({
|
||||
workspace: Workspace;
|
||||
}) => {
|
||||
const titleInputHandleRef = useRef<InlineEditHandle>(null);
|
||||
|
||||
const manager = usePagePropertiesManager(page);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
onOpenChange(false);
|
||||
}, [onOpenChange]);
|
||||
@@ -60,7 +62,6 @@ export const InfoModal = ({
|
||||
<Modal
|
||||
contentOptions={{
|
||||
className: styles.container,
|
||||
'aria-describedby': undefined,
|
||||
}}
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '@affine/component/setting-components';
|
||||
import { Button, IconButton } from '@affine/component/ui/button';
|
||||
import { Loading } from '@affine/component/ui/loading';
|
||||
import { getUpgradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import type { InvoicesQuery } from '@affine/graphql';
|
||||
import {
|
||||
@@ -30,7 +31,7 @@ import {
|
||||
} from '../../../../../atoms';
|
||||
import { useMutation } from '../../../../../hooks/use-mutation';
|
||||
import { useQuery } from '../../../../../hooks/use-query';
|
||||
import { SubscriptionService } from '../../../../../modules/cloud';
|
||||
import { AuthService, SubscriptionService } from '../../../../../modules/cloud';
|
||||
import { mixpanel, popupWindow } from '../../../../../utils';
|
||||
import { SWRErrorBoundary } from '../../../../pure/swr-error-bundary';
|
||||
import { CancelAction, ResumeAction } from '../plans/actions';
|
||||
@@ -194,6 +195,8 @@ const SubscriptionSettings = () => {
|
||||
<SubscriptionSettingSkeleton />
|
||||
)}
|
||||
|
||||
<TypeFormLink />
|
||||
|
||||
{proSubscription !== null ? (
|
||||
proSubscription?.status === SubscriptionStatus.Active && (
|
||||
<>
|
||||
@@ -269,6 +272,45 @@ const SubscriptionSettings = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const TypeFormLink = () => {
|
||||
const t = useI18n();
|
||||
const subscriptionService = useService(SubscriptionService);
|
||||
const authService = useService(AuthService);
|
||||
|
||||
const pro = useLiveData(subscriptionService.subscription.pro$);
|
||||
const ai = useLiveData(subscriptionService.subscription.ai$);
|
||||
const account = useLiveData(authService.session.account$);
|
||||
|
||||
if (!account) return null;
|
||||
if (!pro && !ai) return null;
|
||||
|
||||
const plan = [];
|
||||
if (pro) plan.push(SubscriptionPlan.Pro);
|
||||
if (ai) plan.push(SubscriptionPlan.AI);
|
||||
|
||||
const link = getUpgradeQuestionnaireLink({
|
||||
name: account.info?.name,
|
||||
id: account.id,
|
||||
email: account.email,
|
||||
recurring: pro?.recurring ?? ai?.recurring ?? SubscriptionRecurring.Yearly,
|
||||
plan,
|
||||
});
|
||||
|
||||
return (
|
||||
<SettingRow
|
||||
className={styles.paymentMethod}
|
||||
name={t['com.affine.payment.billing-type-form.title']()}
|
||||
desc={t['com.affine.payment.billing-type-form.description']()}
|
||||
>
|
||||
<a target="_blank" href={link} rel="noreferrer">
|
||||
<Button style={{ padding: '4px 12px' }}>
|
||||
{t['com.affine.payment.billing-type-form.go']()}
|
||||
</Button>
|
||||
</a>
|
||||
</SettingRow>
|
||||
);
|
||||
};
|
||||
|
||||
const BelieverIdentifier = ({ onOpenPlans }: { onOpenPlans?: () => void }) => {
|
||||
const t = useI18n();
|
||||
const subscriptionService = useService(SubscriptionService);
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { getDowngradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { SubscriptionPlan } from '@affine/graphql';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { nanoid } from 'nanoid';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { SubscriptionService } from '../../../../../modules/cloud';
|
||||
import { AuthService, SubscriptionService } from '../../../../../modules/cloud';
|
||||
import { useDowngradeNotify } from '../../../subscription-landing/notify';
|
||||
import { ConfirmLoadingModal, DowngradeModal } from './modals';
|
||||
|
||||
/**
|
||||
@@ -24,9 +27,13 @@ export const CancelAction = ({
|
||||
const [idempotencyKey, setIdempotencyKey] = useState(nanoid());
|
||||
const [isMutating, setIsMutating] = useState(false);
|
||||
const subscription = useService(SubscriptionService).subscription;
|
||||
const authService = useService(AuthService);
|
||||
const downgradeNotify = useDowngradeNotify();
|
||||
|
||||
const downgrade = useAsyncCallback(async () => {
|
||||
try {
|
||||
const account = authService.session.account$.value;
|
||||
const prevRecurring = subscription.pro$.value?.recurring;
|
||||
setIsMutating(true);
|
||||
await subscription.cancelSubscription(idempotencyKey);
|
||||
subscription.revalidate();
|
||||
@@ -41,10 +48,27 @@ export const CancelAction = ({
|
||||
type: subscription.pro$.value?.plan,
|
||||
category: subscription.pro$.value?.recurring,
|
||||
});
|
||||
if (account && prevRecurring) {
|
||||
downgradeNotify(
|
||||
getDowngradeQuestionnaireLink({
|
||||
email: account.email ?? '',
|
||||
id: account.id,
|
||||
name: account.info?.name ?? '',
|
||||
plan: SubscriptionPlan.Pro,
|
||||
recurring: prevRecurring,
|
||||
})
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
setIsMutating(false);
|
||||
}
|
||||
}, [subscription, idempotencyKey, onOpenChange]);
|
||||
}, [
|
||||
authService.session.account$.value,
|
||||
subscription,
|
||||
idempotencyKey,
|
||||
onOpenChange,
|
||||
downgradeNotify,
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Button, type ButtonProps, useConfirmModal } from '@affine/component';
|
||||
import { useDowngradeNotify } from '@affine/core/components/affine/subscription-landing/notify';
|
||||
import { getDowngradeQuestionnaireLink } from '@affine/core/hooks/affine/use-subscription-notify';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { mixpanel } from '@affine/core/utils';
|
||||
import { SubscriptionPlan } from '@affine/graphql';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -14,8 +16,10 @@ export const AICancel = ({ ...btnProps }: AICancelProps) => {
|
||||
const [isMutating, setMutating] = useState(false);
|
||||
const [idempotencyKey, setIdempotencyKey] = useState(nanoid());
|
||||
const subscription = useService(SubscriptionService).subscription;
|
||||
const authService = useService(AuthService);
|
||||
|
||||
const { openConfirmModal } = useConfirmModal();
|
||||
const downgradeNotify = useDowngradeNotify();
|
||||
|
||||
const cancel = useAsyncCallback(async () => {
|
||||
mixpanel.track('PlanChangeStarted', {
|
||||
@@ -51,12 +55,32 @@ export const AICancel = ({ ...btnProps }: AICancelProps) => {
|
||||
segment: 'settings panel',
|
||||
control: 'plan cancel action',
|
||||
});
|
||||
const account = authService.session.account$.value;
|
||||
const prevRecurring = subscription.ai$.value?.recurring;
|
||||
if (account && prevRecurring) {
|
||||
downgradeNotify(
|
||||
getDowngradeQuestionnaireLink({
|
||||
email: account.email,
|
||||
name: account.info?.name,
|
||||
id: account.id,
|
||||
plan: SubscriptionPlan.AI,
|
||||
recurring: prevRecurring,
|
||||
})
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
setMutating(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
}, [openConfirmModal, t, subscription, idempotencyKey]);
|
||||
}, [
|
||||
subscription,
|
||||
openConfirmModal,
|
||||
t,
|
||||
idempotencyKey,
|
||||
authService.session.account$.value,
|
||||
downgradeNotify,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Button onClick={cancel} loading={isMutating} type="primary" {...btnProps}>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Button, type ButtonProps, Skeleton } from '@affine/component';
|
||||
import { generateSubscriptionCallbackLink } from '@affine/core/hooks/affine/use-subscription-notify';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { mixpanel, popupWindow } from '@affine/core/utils';
|
||||
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
@@ -19,6 +20,7 @@ export const AISubscribe = ({
|
||||
const [idempotencyKey, setIdempotencyKey] = useState(nanoid());
|
||||
const [isMutating, setMutating] = useState(false);
|
||||
const [isOpenedExternalWindow, setOpenedExternalWindow] = useState(false);
|
||||
const authService = useService(AuthService);
|
||||
|
||||
const subscriptionService = useService(SubscriptionService);
|
||||
const price = useLiveData(subscriptionService.prices.aiPrice$);
|
||||
@@ -57,7 +59,11 @@ export const AISubscribe = ({
|
||||
idempotencyKey,
|
||||
plan: SubscriptionPlan.AI,
|
||||
coupon: null,
|
||||
successCallbackLink: '/ai-upgrade-success',
|
||||
successCallbackLink: generateSubscriptionCallbackLink(
|
||||
authService.session.account$.value,
|
||||
SubscriptionPlan.AI,
|
||||
SubscriptionRecurring.Yearly
|
||||
),
|
||||
});
|
||||
popupWindow(session);
|
||||
setOpenedExternalWindow(true);
|
||||
@@ -65,7 +71,7 @@ export const AISubscribe = ({
|
||||
} finally {
|
||||
setMutating(false);
|
||||
}
|
||||
}, [idempotencyKey, subscriptionService]);
|
||||
}, [authService, idempotencyKey, subscriptionService]);
|
||||
|
||||
if (!price || !price.yearlyAmount) {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { generateSubscriptionCallbackLink } from '@affine/core/hooks/affine/use-subscription-notify';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
|
||||
import { popupWindow } from '@affine/core/utils';
|
||||
@@ -259,6 +260,7 @@ export const Upgrade = ({
|
||||
const t = useI18n();
|
||||
|
||||
const subscriptionService = useService(SubscriptionService);
|
||||
const authService = useService(AuthService);
|
||||
|
||||
const [idempotencyKey, setIdempotencyKey] = useState(nanoid());
|
||||
|
||||
@@ -293,13 +295,22 @@ export const Upgrade = ({
|
||||
idempotencyKey,
|
||||
plan: SubscriptionPlan.Pro, // Only support prod plan now.
|
||||
coupon: null,
|
||||
successCallbackLink: '/upgrade-success',
|
||||
successCallbackLink: generateSubscriptionCallbackLink(
|
||||
authService.session.account$.value,
|
||||
SubscriptionPlan.Pro,
|
||||
recurring
|
||||
),
|
||||
});
|
||||
setMutating(false);
|
||||
setIdempotencyKey(nanoid());
|
||||
popupWindow(link);
|
||||
setOpenedExternalWindow(true);
|
||||
}, [subscriptionService, recurring, idempotencyKey]);
|
||||
}, [
|
||||
recurring,
|
||||
authService.session.account$.value,
|
||||
subscriptionService,
|
||||
idempotencyKey,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { AuthPageContainer } from '@affine/component/auth-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useSubscriptionNotifyWriter } from '@affine/core/hooks/affine/use-subscription-notify';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import { SubscriptionPlan } from '@affine/graphql';
|
||||
import { Trans, useI18n } from '@affine/i18n';
|
||||
import mixpanel from 'mixpanel-browser';
|
||||
import { type ReactNode, useCallback, useEffect } from 'react';
|
||||
import { type ReactNode, useCallback } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import * as styles from './styles.css';
|
||||
@@ -58,13 +57,7 @@ const UpgradeSuccessLayout = ({
|
||||
|
||||
export const CloudUpgradeSuccess = () => {
|
||||
const t = useI18n();
|
||||
useEffect(() => {
|
||||
mixpanel.track('PlanUpgradeSucceeded', {
|
||||
segment: 'settings panel',
|
||||
control: 'plan upgrade action',
|
||||
plan: SubscriptionPlan.Pro,
|
||||
});
|
||||
}, []);
|
||||
useSubscriptionNotifyWriter();
|
||||
return (
|
||||
<UpgradeSuccessLayout
|
||||
title={t['com.affine.payment.upgrade-success-page.title']()}
|
||||
@@ -75,13 +68,7 @@ export const CloudUpgradeSuccess = () => {
|
||||
|
||||
export const AIUpgradeSuccess = () => {
|
||||
const t = useI18n();
|
||||
useEffect(() => {
|
||||
mixpanel.track('PlanUpgradeSucceeded', {
|
||||
segment: 'settings panel',
|
||||
control: 'plan upgrade action',
|
||||
plan: SubscriptionPlan.Pro,
|
||||
});
|
||||
}, []);
|
||||
useSubscriptionNotifyWriter();
|
||||
return (
|
||||
<UpgradeSuccessLayout
|
||||
title={t['com.affine.payment.ai-upgrade-success-page.title']()}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const notifyHeader = style({
|
||||
fontWeight: 500,
|
||||
fontSize: 15,
|
||||
});
|
||||
|
||||
export const notifyFooter = style({
|
||||
display: 'flex',
|
||||
justifyContent: 'end',
|
||||
gap: 12,
|
||||
paddingTop: 8,
|
||||
});
|
||||
|
||||
export const actionButton = style({
|
||||
fontSize: cssVar('fontSm'),
|
||||
fontWeight: 500,
|
||||
lineHeight: '22px',
|
||||
});
|
||||
export const confirmButton = style({
|
||||
selectors: {
|
||||
'&.plain': {
|
||||
color: cssVar('brandColor'),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const cancelButton = style({
|
||||
selectors: {
|
||||
'&.plain': {
|
||||
color: cssVar('textPrimaryColor'),
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
import { Button, notify } from '@affine/component';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import {
|
||||
actionButton,
|
||||
cancelButton,
|
||||
confirmButton,
|
||||
notifyFooter,
|
||||
notifyHeader,
|
||||
} from './notify.css';
|
||||
|
||||
interface SubscriptionChangedNotifyFooterProps {
|
||||
onCancel: () => void;
|
||||
onConfirm?: () => void;
|
||||
to: string;
|
||||
okText: string;
|
||||
cancelText: string;
|
||||
}
|
||||
|
||||
const SubscriptionChangedNotifyFooter = ({
|
||||
to,
|
||||
okText,
|
||||
cancelText,
|
||||
onCancel,
|
||||
onConfirm,
|
||||
}: SubscriptionChangedNotifyFooterProps) => {
|
||||
return (
|
||||
<div className={notifyFooter}>
|
||||
<Button
|
||||
className={clsx(actionButton, cancelButton)}
|
||||
size={'default'}
|
||||
onClick={onCancel}
|
||||
type="plain"
|
||||
>
|
||||
{cancelText}
|
||||
</Button>
|
||||
<a href={to} target="_blank" rel="noreferrer">
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
className={clsx(actionButton, confirmButton)}
|
||||
type="plain"
|
||||
>
|
||||
{okText}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const isDesktop = environment.isDesktop;
|
||||
export const useUpgradeNotify = () => {
|
||||
const t = useI18n();
|
||||
const prevNotifyIdRef = useRef<string | number | null>(null);
|
||||
|
||||
return useCallback(
|
||||
(link: string) => {
|
||||
prevNotifyIdRef.current && notify.dismiss(prevNotifyIdRef.current);
|
||||
const id = notify(
|
||||
{
|
||||
title: (
|
||||
<span className={notifyHeader}>
|
||||
{t['com.affine.payment.upgrade-success-notify.title']()}
|
||||
</span>
|
||||
),
|
||||
message: t['com.affine.payment.upgrade-success-notify.content'](),
|
||||
alignMessage: 'title',
|
||||
icon: null,
|
||||
footer: (
|
||||
<SubscriptionChangedNotifyFooter
|
||||
to={link}
|
||||
okText={
|
||||
isDesktop
|
||||
? t['com.affine.payment.upgrade-success-notify.ok-client']()
|
||||
: t['com.affine.payment.upgrade-success-notify.ok-web']()
|
||||
}
|
||||
cancelText={t[
|
||||
'com.affine.payment.upgrade-success-notify.later'
|
||||
]()}
|
||||
onCancel={() => notify.dismiss(id)}
|
||||
onConfirm={() => notify.dismiss(id)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{ duration: 24 * 60 * 60 * 1000 }
|
||||
);
|
||||
prevNotifyIdRef.current = id;
|
||||
},
|
||||
[t]
|
||||
);
|
||||
};
|
||||
|
||||
export const useDowngradeNotify = () => {
|
||||
const t = useI18n();
|
||||
const prevNotifyIdRef = useRef<string | number | null>(null);
|
||||
|
||||
return useCallback(
|
||||
(link: string) => {
|
||||
prevNotifyIdRef.current && notify.dismiss(prevNotifyIdRef.current);
|
||||
const id = notify(
|
||||
{
|
||||
title: (
|
||||
<span className={notifyHeader}>
|
||||
{t['com.affine.payment.downgraded-notify.title']()}
|
||||
</span>
|
||||
),
|
||||
message: t['com.affine.payment.downgraded-notify.content'](),
|
||||
alignMessage: 'title',
|
||||
icon: null,
|
||||
footer: (
|
||||
<SubscriptionChangedNotifyFooter
|
||||
to={link}
|
||||
okText={
|
||||
isDesktop
|
||||
? t['com.affine.payment.downgraded-notify.ok-client']()
|
||||
: t['com.affine.payment.downgraded-notify.ok-web']()
|
||||
}
|
||||
cancelText={t['com.affine.payment.downgraded-notify.later']()}
|
||||
onCancel={() => notify.dismiss(id)}
|
||||
onConfirm={() => notify.dismiss(id)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{ duration: 24 * 60 * 60 * 1000 }
|
||||
);
|
||||
prevNotifyIdRef.current = id;
|
||||
},
|
||||
[t]
|
||||
);
|
||||
};
|
||||
@@ -44,6 +44,38 @@ export function createChatSession({
|
||||
});
|
||||
}
|
||||
|
||||
async function resizeImage(blob: Blob | File): Promise<Blob | null> {
|
||||
let src = '';
|
||||
try {
|
||||
src = URL.createObjectURL(blob);
|
||||
const img = new Image();
|
||||
img.src = src;
|
||||
await new Promise(resolve => {
|
||||
img.onload = resolve;
|
||||
});
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
// keep aspect ratio
|
||||
const scale = Math.min(1024 / img.width, 1024 / img.height);
|
||||
canvas.width = Math.floor(img.width * scale);
|
||||
canvas.height = Math.floor(img.height * scale);
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) {
|
||||
ctx.imageSmoothingQuality = 'high';
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
return new Promise(resolve =>
|
||||
canvas.toBlob(blob => resolve(blob), 'image/jpeg', 0.8)
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
if (src) URL.revokeObjectURL(src);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function createSessionMessage({
|
||||
docId,
|
||||
workspaceId,
|
||||
@@ -77,17 +109,17 @@ async function createSessionMessage({
|
||||
attachment => typeof attachment === 'string'
|
||||
) as [string[], (Blob | File)[]];
|
||||
options.attachments = stringAttachments;
|
||||
options.blobs = await Promise.all(
|
||||
blobs.map(async blob => {
|
||||
if (blob instanceof File) {
|
||||
return blob;
|
||||
} else {
|
||||
return new File([blob], sessionId, {
|
||||
type: blob.type,
|
||||
options.blobs = (
|
||||
await Promise.all(
|
||||
blobs.map(resizeImage).map(async blob => {
|
||||
const file = await blob;
|
||||
if (!file) return null;
|
||||
return new File([file], sessionId, {
|
||||
type: file.type,
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
).filter(Boolean) as File[];
|
||||
}
|
||||
if (retry)
|
||||
return {
|
||||
|
||||
@@ -9,6 +9,11 @@ export const container = style({
|
||||
paddingLeft: cssVar('--affine-editor-side-padding', '24'),
|
||||
paddingRight: cssVar('--affine-editor-side-padding', '24'),
|
||||
fontSize: cssVar('--affine-font-base'),
|
||||
'@container': {
|
||||
[`viewport (width <= 640px)`]: {
|
||||
padding: '0 24px',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const dividerContainer = style({
|
||||
|
||||
@@ -97,9 +97,7 @@ const usePatchSpecs = (page: Doc, shared: boolean, mode: DocMode) => {
|
||||
patchReferenceRenderer(patched, reactToLit, referenceRenderer),
|
||||
confirmModal
|
||||
);
|
||||
if (!page.readonly) {
|
||||
patched = patchPeekViewService(patched, peekViewService);
|
||||
}
|
||||
patched = patchPeekViewService(patched, peekViewService);
|
||||
if (!page.readonly) {
|
||||
patched = patchQuickSearchService(patched, framework);
|
||||
}
|
||||
|
||||
@@ -514,7 +514,7 @@ export function patchQuickSearchService(
|
||||
@customElement('affine-linked-doc-ref-block')
|
||||
// @ts-expect-error ignore private warning for overriding _load
|
||||
export class LinkedDocBlockComponent extends EmbedLinkedDocBlockComponent {
|
||||
override _load() {
|
||||
override async _load() {
|
||||
this.isBannerEmpty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { FavoriteTag } from '@affine/core/components/page-list';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import { toast } from '@affine/core/utils';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export interface FavoriteButtonProps {
|
||||
@@ -12,11 +11,7 @@ export interface FavoriteButtonProps {
|
||||
|
||||
export const useFavorite = (pageId: string) => {
|
||||
const t = useI18n();
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const docCollection = workspace.docCollection;
|
||||
const currentPage = docCollection.getDoc(pageId);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
assertExists(currentPage);
|
||||
|
||||
const favorite = useLiveData(favAdapter.isFavorite$(pageId, 'doc'));
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import type { ReactNode } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import * as styles from './edit-collection.css';
|
||||
import { PagesMode } from './pages-mode';
|
||||
import { RulesMode } from './rules-mode';
|
||||
import { SelectPage } from './select-page';
|
||||
|
||||
export type EditCollectionMode = 'page' | 'rule';
|
||||
|
||||
@@ -23,9 +23,6 @@ export interface EditCollectionModalProps {
|
||||
}
|
||||
|
||||
const contentOptions: DialogContentProps = {
|
||||
onPointerDownOutside: e => {
|
||||
e.preventDefault();
|
||||
},
|
||||
style: {
|
||||
padding: 0,
|
||||
maxWidth: 944,
|
||||
@@ -60,6 +57,7 @@ export const EditCollectionModal = ({
|
||||
width="calc(100% - 64px)"
|
||||
height="80%"
|
||||
contentOptions={contentOptions}
|
||||
persistent
|
||||
>
|
||||
{open && init ? (
|
||||
<EditCollection
|
||||
@@ -110,6 +108,12 @@ export const EditCollection = ({
|
||||
allowList: init.allowList,
|
||||
});
|
||||
}, [init.allowList, init.filterList, value]);
|
||||
const onIdsChange = useCallback(
|
||||
(ids: string[]) => {
|
||||
onChange({ ...value, allowList: ids });
|
||||
},
|
||||
[value]
|
||||
);
|
||||
const buttons = useMemo(
|
||||
() => (
|
||||
<>
|
||||
@@ -164,13 +168,13 @@ export const EditCollection = ({
|
||||
className={styles.collectionEditContainer}
|
||||
>
|
||||
{mode === 'page' ? (
|
||||
<PagesMode
|
||||
collection={value}
|
||||
updateCollection={onChange}
|
||||
switchMode={switchMode}
|
||||
buttons={buttons}
|
||||
<SelectPage
|
||||
allPageListConfig={config}
|
||||
></PagesMode>
|
||||
init={value.allowList}
|
||||
onChange={onIdsChange}
|
||||
header={switchMode}
|
||||
buttons={buttons}
|
||||
/>
|
||||
) : (
|
||||
<RulesMode
|
||||
allPageListConfig={config}
|
||||
|
||||
@@ -12,9 +12,14 @@ export const useSelectPage = ({
|
||||
init: string[];
|
||||
onConfirm: (ids: string[]) => void;
|
||||
}>();
|
||||
const close = useCallback(() => {
|
||||
onChange(undefined);
|
||||
const close = useCallback((open: boolean) => {
|
||||
if (!open) {
|
||||
onChange(undefined);
|
||||
}
|
||||
}, []);
|
||||
const handleCancel = useCallback(() => {
|
||||
close(false);
|
||||
}, [close]);
|
||||
return {
|
||||
node: (
|
||||
<Modal
|
||||
@@ -38,7 +43,7 @@ export const useSelectPage = ({
|
||||
allPageListConfig={allPageListConfig}
|
||||
init={value.init}
|
||||
onConfirm={value.onConfirm}
|
||||
onCancel={close}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
) : null}
|
||||
</Modal>
|
||||
@@ -48,7 +53,7 @@ export const useSelectPage = ({
|
||||
onChange({
|
||||
init,
|
||||
onConfirm: list => {
|
||||
close();
|
||||
close(false);
|
||||
res(list);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
import { Menu } from '@affine/component';
|
||||
import { FavoriteItemsAdapter } from '@affine/core/modules/properties';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { FilterIcon } from '@blocksuite/icons/rc';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { FilterList } from '../../filter/filter-list';
|
||||
import { VariableSelect } from '../../filter/vars';
|
||||
import { usePageHeaderColsDef } from '../../header-col-def';
|
||||
import { PageListItemRenderer } from '../../page-group';
|
||||
import { ListTableHeader } from '../../page-header';
|
||||
import type { ListItem } from '../../types';
|
||||
import { VirtualizedList } from '../../virtualized-list';
|
||||
import type { AllPageListConfig } from './edit-collection';
|
||||
import * as styles from './edit-collection.css';
|
||||
import { EmptyList } from './select-page';
|
||||
import { useFilter } from './use-filter';
|
||||
import { useSearch } from './use-search';
|
||||
|
||||
export const PagesMode = ({
|
||||
switchMode,
|
||||
collection,
|
||||
updateCollection,
|
||||
buttons,
|
||||
allPageListConfig,
|
||||
}: {
|
||||
collection: Collection;
|
||||
updateCollection: (collection: Collection) => void;
|
||||
buttons: ReactNode;
|
||||
switchMode: ReactNode;
|
||||
allPageListConfig: AllPageListConfig;
|
||||
}) => {
|
||||
const t = useI18n();
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favorites = useLiveData(favAdapter.favorites$);
|
||||
const {
|
||||
showFilter,
|
||||
filters,
|
||||
updateFilters,
|
||||
clickFilter,
|
||||
createFilter,
|
||||
filteredList,
|
||||
} = useFilter(
|
||||
allPageListConfig.allPages.map(meta => ({
|
||||
meta,
|
||||
publicMode: allPageListConfig.getPublicMode(meta.id),
|
||||
favorite: favorites.some(f => f.id === meta.id),
|
||||
}))
|
||||
);
|
||||
const pageHeaderColsDef = usePageHeaderColsDef();
|
||||
const { searchText, updateSearchText, searchedList } =
|
||||
useSearch(filteredList);
|
||||
const clearSelected = useCallback(() => {
|
||||
updateCollection({
|
||||
...collection,
|
||||
allowList: [],
|
||||
});
|
||||
}, [collection, updateCollection]);
|
||||
const pageOperationsRenderer = useCallback(
|
||||
(item: ListItem) => {
|
||||
const page = item as DocMeta;
|
||||
return allPageListConfig.favoriteRender(page);
|
||||
},
|
||||
[allPageListConfig]
|
||||
);
|
||||
|
||||
const pageItemRenderer = useCallback((item: ListItem) => {
|
||||
return <PageListItemRenderer {...item} />;
|
||||
}, []);
|
||||
const pageHeaderRenderer = useCallback(() => {
|
||||
return <ListTableHeader headerCols={pageHeaderColsDef} />;
|
||||
}, [pageHeaderColsDef]);
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
value={searchText}
|
||||
onChange={e => updateSearchText(e.target.value)}
|
||||
className={styles.rulesTitle}
|
||||
style={{
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
}}
|
||||
placeholder={t['com.affine.editCollection.search.placeholder']()}
|
||||
></input>
|
||||
<div className={styles.pagesList}>
|
||||
<div className={styles.pagesTab}>
|
||||
<div className={styles.pagesTabContent}>
|
||||
{switchMode}
|
||||
{!showFilter && filters.length === 0 ? (
|
||||
<Menu
|
||||
items={
|
||||
<VariableSelect
|
||||
propertiesMeta={
|
||||
allPageListConfig.docCollection.meta.properties
|
||||
}
|
||||
selected={filters}
|
||||
onSelect={createFilter}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<FilterIcon
|
||||
className={clsx(styles.icon, styles.button)}
|
||||
onClick={clickFilter}
|
||||
width={24}
|
||||
height={24}
|
||||
></FilterIcon>
|
||||
</div>
|
||||
</Menu>
|
||||
) : (
|
||||
<FilterIcon
|
||||
className={clsx(styles.icon, styles.button)}
|
||||
onClick={clickFilter}
|
||||
width={24}
|
||||
height={24}
|
||||
></FilterIcon>
|
||||
)}
|
||||
</div>
|
||||
{showFilter ? (
|
||||
<div style={{ padding: '12px 16px 16px' }}>
|
||||
<FilterList
|
||||
propertiesMeta={allPageListConfig.docCollection.meta.properties}
|
||||
value={filters}
|
||||
onChange={updateFilters}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{searchedList.length ? (
|
||||
<VirtualizedList
|
||||
className={styles.pageList}
|
||||
items={searchedList}
|
||||
docCollection={allPageListConfig.docCollection}
|
||||
selectable
|
||||
onSelectedIdsChange={ids => {
|
||||
updateCollection({
|
||||
...collection,
|
||||
allowList: ids,
|
||||
});
|
||||
}}
|
||||
itemRenderer={pageItemRenderer}
|
||||
operationsRenderer={pageOperationsRenderer}
|
||||
headerRenderer={pageHeaderRenderer}
|
||||
selectedIds={collection.allowList}
|
||||
isPreferredEdgeless={allPageListConfig.isEdgeless}
|
||||
/>
|
||||
) : (
|
||||
<EmptyList search={searchText} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.pagesBottom}>
|
||||
<div className={styles.pagesBottomLeft}>
|
||||
<div className={styles.selectedCountTips}>
|
||||
{t['com.affine.selectPage.selected']()}
|
||||
<span
|
||||
style={{ marginLeft: 7 }}
|
||||
className={styles.previewCountTipsHighlight}
|
||||
>
|
||||
{collection.allowList.length}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={clsx(styles.button, styles.bottomButton)}
|
||||
style={{ fontSize: 12, lineHeight: '20px' }}
|
||||
onClick={clearSelected}
|
||||
>
|
||||
{t['com.affine.editCollection.pages.clear']()}
|
||||
</div>
|
||||
</div>
|
||||
<div>{buttons}</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -5,10 +5,13 @@ import { FilterIcon } from '@blocksuite/icons/rc';
|
||||
import type { DocMeta } from '@blocksuite/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { type ReactNode, useCallback, useState } from 'react';
|
||||
|
||||
import { FilterList } from '../../filter';
|
||||
import { VariableSelect } from '../../filter/vars';
|
||||
import { usePageHeaderColsDef } from '../../header-col-def';
|
||||
import { PageListItemRenderer } from '../../page-group';
|
||||
import { ListTableHeader } from '../../page-header';
|
||||
import type { ListItem } from '../../types';
|
||||
import { VirtualizedList } from '../../virtualized-list';
|
||||
import { AffineShapeIcon } from '../affine-shape';
|
||||
@@ -22,22 +25,38 @@ export const SelectPage = ({
|
||||
init,
|
||||
onConfirm,
|
||||
onCancel,
|
||||
onChange: propsOnChange,
|
||||
confirmText,
|
||||
header,
|
||||
buttons,
|
||||
}: {
|
||||
allPageListConfig: AllPageListConfig;
|
||||
init: string[];
|
||||
onConfirm: (pageIds: string[]) => void;
|
||||
onCancel: () => void;
|
||||
onConfirm?: (pageIds: string[]) => void;
|
||||
onCancel?: () => void;
|
||||
onChange?: (values: string[]) => void;
|
||||
confirmText?: ReactNode;
|
||||
header?: ReactNode;
|
||||
buttons?: ReactNode;
|
||||
}) => {
|
||||
const t = useI18n();
|
||||
const [value, onChange] = useState(init);
|
||||
const [value, setValue] = useState(init);
|
||||
const onChange = useCallback(
|
||||
(value: string[]) => {
|
||||
propsOnChange?.(value);
|
||||
setValue(value);
|
||||
},
|
||||
[propsOnChange]
|
||||
);
|
||||
const confirm = useCallback(() => {
|
||||
onConfirm(value);
|
||||
onConfirm?.(value);
|
||||
}, [value, onConfirm]);
|
||||
const clearSelected = useCallback(() => {
|
||||
onChange([]);
|
||||
}, []);
|
||||
}, [onChange]);
|
||||
const favAdapter = useService(FavoriteItemsAdapter);
|
||||
const favourites = useLiveData(favAdapter.favorites$);
|
||||
const pageHeaderColsDef = usePageHeaderColsDef();
|
||||
const {
|
||||
clickFilter,
|
||||
createFilter,
|
||||
@@ -63,6 +82,14 @@ export const SelectPage = ({
|
||||
[allPageListConfig]
|
||||
);
|
||||
|
||||
const pageHeaderRenderer = useCallback(() => {
|
||||
return <ListTableHeader headerCols={pageHeaderColsDef} />;
|
||||
}, [pageHeaderColsDef]);
|
||||
|
||||
const pageItemRenderer = useCallback((item: ListItem) => {
|
||||
return <PageListItemRenderer {...item} />;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<input
|
||||
@@ -73,9 +100,11 @@ export const SelectPage = ({
|
||||
></input>
|
||||
<div className={styles.pagesTab}>
|
||||
<div className={styles.pagesTabContent}>
|
||||
<div style={{ fontSize: 12, lineHeight: '20px', fontWeight: 600 }}>
|
||||
{t['com.affine.selectPage.title']()}
|
||||
</div>
|
||||
{header ?? (
|
||||
<div style={{ fontSize: 12, lineHeight: '20px', fontWeight: 600 }}>
|
||||
{t['com.affine.selectPage.title']()}
|
||||
</div>
|
||||
)}
|
||||
{!showFilter && filters.length === 0 ? (
|
||||
<Menu
|
||||
items={
|
||||
@@ -125,6 +154,8 @@ export const SelectPage = ({
|
||||
selectedIds={value}
|
||||
isPreferredEdgeless={allPageListConfig.isEdgeless}
|
||||
operationsRenderer={operationsRenderer}
|
||||
itemRenderer={pageItemRenderer}
|
||||
headerRenderer={pageHeaderRenderer}
|
||||
/>
|
||||
) : (
|
||||
<EmptyList search={searchText} />
|
||||
@@ -150,18 +181,22 @@ export const SelectPage = ({
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Button size="large" onClick={onCancel}>
|
||||
{t['com.affine.editCollection.button.cancel']()}
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.confirmButton}
|
||||
size="large"
|
||||
data-testid="save-collection"
|
||||
type="primary"
|
||||
onClick={confirm}
|
||||
>
|
||||
{t['Confirm']()}
|
||||
</Button>
|
||||
{buttons ?? (
|
||||
<>
|
||||
<Button size="large" onClick={onCancel}>
|
||||
{t['com.affine.editCollection.button.cancel']()}
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.confirmButton}
|
||||
size="large"
|
||||
data-testid="save-collection"
|
||||
type="primary"
|
||||
onClick={confirm}
|
||||
>
|
||||
{confirmText ?? t['Confirm']()}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,18 +11,22 @@ export const useEditCollection = () => {
|
||||
mode?: 'page' | 'rule';
|
||||
onConfirm: (collection: Collection) => void;
|
||||
}>();
|
||||
const close = useCallback(() => setData(undefined), []);
|
||||
const close = useCallback((open: boolean) => {
|
||||
if (!open) {
|
||||
setData(undefined);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return {
|
||||
node: data ? (
|
||||
node: (
|
||||
<EditCollectionModal
|
||||
init={data.collection}
|
||||
init={data?.collection}
|
||||
open={!!data}
|
||||
mode={data.mode}
|
||||
mode={data?.mode}
|
||||
onOpenChange={close}
|
||||
onConfirm={data.onConfirm}
|
||||
onConfirm={data?.onConfirm ?? (() => {})}
|
||||
/>
|
||||
) : null,
|
||||
),
|
||||
open: (
|
||||
collection: Collection,
|
||||
mode?: EditCollectionMode
|
||||
@@ -50,19 +54,23 @@ export const useEditCollectionName = ({
|
||||
name: string;
|
||||
onConfirm: (name: string) => void;
|
||||
}>();
|
||||
const close = useCallback(() => setData(undefined), []);
|
||||
const close = useCallback((open: boolean) => {
|
||||
if (!open) {
|
||||
setData(undefined);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return {
|
||||
node: data ? (
|
||||
node: (
|
||||
<CreateCollectionModal
|
||||
showTips={showTips}
|
||||
title={title}
|
||||
init={data.name}
|
||||
init={data?.name ?? ''}
|
||||
open={!!data}
|
||||
onOpenChange={close}
|
||||
onConfirm={data.onConfirm}
|
||||
onConfirm={data?.onConfirm ?? (() => {})}
|
||||
/>
|
||||
) : null,
|
||||
),
|
||||
open: (name: string): Promise<string> =>
|
||||
new Promise<string>(res => {
|
||||
setData({
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
import { useUpgradeNotify } from '@affine/core/components/affine/subscription-landing/notify';
|
||||
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
|
||||
import mixpanel from 'mixpanel-browser';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { type AuthAccountInfo } from '../../modules/cloud';
|
||||
|
||||
const separator = '::';
|
||||
const recoverSeparator = nanoid();
|
||||
const localStorageKey = 'subscription-succeed-info';
|
||||
|
||||
const typeFormUrl = 'https://6dxre9ihosp.typeform.com/to';
|
||||
const typeFormUpgradeId = 'mUMGGQS8';
|
||||
const typeFormDowngradeId = 'RvD9AoRg';
|
||||
|
||||
type TypeFormInfo = {
|
||||
id: string;
|
||||
name?: string;
|
||||
email?: string;
|
||||
plan: string | string[];
|
||||
recurring: string;
|
||||
};
|
||||
const getTypeFormLink = (id: string, info: TypeFormInfo) => {
|
||||
const plans = Array.isArray(info.plan) ? info.plan : [info.plan];
|
||||
const product_id = plans
|
||||
.map(plan => (plan === SubscriptionPlan.AI ? 'ai' : 'cloud'))
|
||||
.join('-');
|
||||
const product_price =
|
||||
info.recurring === SubscriptionRecurring.Monthly
|
||||
? 'monthly'
|
||||
: info.recurring === SubscriptionRecurring.Lifetime
|
||||
? 'lifeTime'
|
||||
: 'annually';
|
||||
return `${typeFormUrl}/${id}#email=${info.email ?? ''}&name=${info.name ?? 'Unknown'}&user_id=${info.id}&product_id=${product_id}&product_price=${product_price}`;
|
||||
};
|
||||
export const getUpgradeQuestionnaireLink = (info: TypeFormInfo) =>
|
||||
getTypeFormLink(typeFormUpgradeId, info);
|
||||
export const getDowngradeQuestionnaireLink = (info: TypeFormInfo) =>
|
||||
getTypeFormLink(typeFormDowngradeId, info);
|
||||
|
||||
/**
|
||||
* Generate subscription callback link with account info
|
||||
*/
|
||||
export const generateSubscriptionCallbackLink = (
|
||||
account: AuthAccountInfo | null,
|
||||
plan: SubscriptionPlan,
|
||||
recurring: SubscriptionRecurring
|
||||
) => {
|
||||
if (account === null) {
|
||||
throw new Error('Account is required');
|
||||
}
|
||||
const baseUrl =
|
||||
plan === SubscriptionPlan.AI ? '/ai-upgrade-success' : '/upgrade-success';
|
||||
|
||||
let name = account?.info?.name ?? '';
|
||||
if (name.includes(separator)) {
|
||||
name = name.replaceAll(separator, recoverSeparator);
|
||||
}
|
||||
|
||||
const query = [
|
||||
plan,
|
||||
recurring,
|
||||
account.id,
|
||||
account.email,
|
||||
account.info?.name ?? '',
|
||||
].join(separator);
|
||||
|
||||
return `${baseUrl}?info=${encodeURIComponent(query)}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse subscription callback query.info
|
||||
* @returns
|
||||
*/
|
||||
export const parseSubscriptionCallbackLink = (query: string) => {
|
||||
const [plan, recurring, id, email, rawName] =
|
||||
decodeURIComponent(query).split(separator);
|
||||
const name = rawName.replaceAll(recoverSeparator, separator);
|
||||
|
||||
return {
|
||||
plan: plan as SubscriptionPlan,
|
||||
recurring: recurring as SubscriptionRecurring,
|
||||
account: {
|
||||
id,
|
||||
email,
|
||||
info: {
|
||||
name,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to parse subscription callback link, and save to local storage and delete the query
|
||||
*/
|
||||
export const useSubscriptionNotifyWriter = () => {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
const query = searchParams.get('info');
|
||||
if (query) {
|
||||
localStorage.setItem(localStorageKey, query);
|
||||
searchParams.delete('info');
|
||||
}
|
||||
}, [searchParams]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to read and parse subscription info from localStorage
|
||||
*/
|
||||
export const useSubscriptionNotifyReader = () => {
|
||||
const upgradeNotify = useUpgradeNotify();
|
||||
|
||||
const readAndNotify = useCallback(() => {
|
||||
const query = localStorage.getItem(localStorageKey);
|
||||
if (!query) return;
|
||||
|
||||
try {
|
||||
const { plan, recurring, account } = parseSubscriptionCallbackLink(query);
|
||||
const link = getUpgradeQuestionnaireLink({
|
||||
id: account.id,
|
||||
email: account.email,
|
||||
name: account.info?.name ?? '',
|
||||
plan,
|
||||
recurring,
|
||||
});
|
||||
upgradeNotify(link);
|
||||
localStorage.removeItem(localStorageKey);
|
||||
|
||||
// mixpanel
|
||||
mixpanel.track('PlanUpgradeSucceeded', {
|
||||
segment: 'settings panel',
|
||||
control: 'plan upgrade action',
|
||||
plan: plan,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Failed to parse subscription callback link', err);
|
||||
}
|
||||
}, [upgradeNotify]);
|
||||
|
||||
useEffect(() => {
|
||||
readAndNotify();
|
||||
window.addEventListener('focus', readAndNotify);
|
||||
return () => {
|
||||
window.removeEventListener('focus', readAndNotify);
|
||||
};
|
||||
}, [readAndNotify]);
|
||||
};
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
useGlobalDNDHelper,
|
||||
} from '../hooks/affine/use-global-dnd-helper';
|
||||
import { useRegisterFindInPageCommands } from '../hooks/affine/use-register-find-in-page-commands';
|
||||
import { useSubscriptionNotifyReader } from '../hooks/affine/use-subscription-notify';
|
||||
import { useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||
import { useRegisterWorkspaceCommands } from '../hooks/use-register-workspace-commands';
|
||||
import { useRegisterNavigationCommands } from '../modules/navigation/view/use-register-navigation-commands';
|
||||
@@ -119,14 +120,18 @@ export const WorkspaceLayoutInner = ({ children }: PropsWithChildren) => {
|
||||
currentWorkspace.docCollection,
|
||||
templateBlob
|
||||
);
|
||||
doc.resetHistory();
|
||||
if (doc) {
|
||||
doc.resetHistory();
|
||||
}
|
||||
|
||||
return { doc, mode };
|
||||
}).pipe(
|
||||
timeout(10000 /* 10s */),
|
||||
mergeMap(({ mode, doc }) => {
|
||||
docsList.setMode(doc.id, mode as DocMode);
|
||||
workbench.openDoc(doc.id);
|
||||
if (doc) {
|
||||
docsList.setMode(doc.id, mode as DocMode);
|
||||
workbench.openDoc(doc.id);
|
||||
}
|
||||
return EMPTY;
|
||||
}),
|
||||
onStart(() => {
|
||||
@@ -164,6 +169,7 @@ export const WorkspaceLayoutInner = ({ children }: PropsWithChildren) => {
|
||||
workbench,
|
||||
]);
|
||||
|
||||
useSubscriptionNotifyReader();
|
||||
useRegisterWorkspaceCommands();
|
||||
useRegisterNavigationCommands();
|
||||
useRegisterFindInPageCommands();
|
||||
|
||||
@@ -419,14 +419,18 @@ const ImagePreviewModalImpl = ({
|
||||
icon={<CopyIcon />}
|
||||
onClick={copyHandler}
|
||||
/>
|
||||
<div className={styles.dividerStyle}></div>
|
||||
<ButtonWithTooltip
|
||||
data-testid="delete-button"
|
||||
tooltip="Delete"
|
||||
icon={<DeleteIcon />}
|
||||
disabled={blocks.length === 0}
|
||||
onClick={() => deleteHandler(cursor)}
|
||||
/>
|
||||
{blockModel && !blockModel.doc.readonly && (
|
||||
<>
|
||||
<div className={styles.dividerStyle}></div>
|
||||
<ButtonWithTooltip
|
||||
data-testid="delete-button"
|
||||
tooltip="Delete"
|
||||
icon={<DeleteIcon />}
|
||||
disabled={blocks.length === 0}
|
||||
onClick={() => deleteHandler(cursor)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,7 @@ const getRendererProps = (
|
||||
activePeekView?.target instanceof HTMLElement
|
||||
? activePeekView.target
|
||||
: undefined,
|
||||
padding: activePeekView.info.type === 'doc',
|
||||
padding: activePeekView.info.type !== 'image',
|
||||
dialogFrame: activePeekView.info.type !== 'image',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const highlightText = style({
|
||||
whiteSpace: 'pre',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
});
|
||||
|
||||
@@ -33,6 +33,7 @@ import { AppContainer } from '../../components/affine/app-container';
|
||||
import { PageDetailEditor } from '../../components/page-detail-editor';
|
||||
import { SharePageNotFoundError } from '../../components/share-page-not-found-error';
|
||||
import { MainContainer } from '../../components/workspace';
|
||||
import { PeekViewManagerModal } from '../../modules/peek-view';
|
||||
import { CloudBlobStorage } from '../../modules/workspace-engine/impls/engine/blob-cloud';
|
||||
import * as styles from './share-detail-page.css';
|
||||
import { ShareFooter } from './share-footer';
|
||||
@@ -253,6 +254,7 @@ export const Component = () => {
|
||||
</div>
|
||||
</div>
|
||||
</MainContainer>
|
||||
<PeekViewManagerModal />
|
||||
</AppContainer>
|
||||
</FrameworkScope>
|
||||
</FrameworkScope>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { EMPTY, mergeMap, switchMap } from 'rxjs';
|
||||
|
||||
import { generateSubscriptionCallbackLink } from '../hooks/affine/use-subscription-notify';
|
||||
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||
import { AuthService, SubscriptionService } from '../modules/cloud';
|
||||
import { mixpanel } from '../utils';
|
||||
@@ -58,21 +59,27 @@ export const Component = () => {
|
||||
category: recurring,
|
||||
});
|
||||
try {
|
||||
const account = authService.session.account$.value;
|
||||
// should never reach
|
||||
if (!account) throw new Error('No account');
|
||||
const targetPlan =
|
||||
plan?.toLowerCase() === 'ai'
|
||||
? SubscriptionPlan.AI
|
||||
: SubscriptionPlan.Pro;
|
||||
const targetRecurring =
|
||||
recurring?.toLowerCase() === 'monthly'
|
||||
? SubscriptionRecurring.Monthly
|
||||
: SubscriptionRecurring.Yearly;
|
||||
const checkout = await subscriptionService.createCheckoutSession({
|
||||
idempotencyKey,
|
||||
plan:
|
||||
plan?.toLowerCase() === 'ai'
|
||||
? SubscriptionPlan.AI
|
||||
: SubscriptionPlan.Pro,
|
||||
plan: targetPlan,
|
||||
coupon: null,
|
||||
recurring:
|
||||
recurring?.toLowerCase() === 'monthly'
|
||||
? SubscriptionRecurring.Monthly
|
||||
: SubscriptionRecurring.Yearly,
|
||||
successCallbackLink:
|
||||
plan?.toLowerCase() === 'ai'
|
||||
? '/ai-upgrade-success'
|
||||
: '/upgrade-success',
|
||||
recurring: targetRecurring,
|
||||
successCallbackLink: generateSubscriptionCallbackLink(
|
||||
account,
|
||||
targetPlan,
|
||||
targetRecurring
|
||||
),
|
||||
});
|
||||
setMessage('Redirecting...');
|
||||
location.href = checkout;
|
||||
|
||||
@@ -96,10 +96,12 @@ export const Component = (): ReactElement => {
|
||||
);
|
||||
console.log(
|
||||
'imported docs',
|
||||
newDocs.map(doc => ({
|
||||
id: doc.id,
|
||||
title: doc.meta?.title,
|
||||
}))
|
||||
newDocs
|
||||
.filter(doc => !!doc)
|
||||
.map(doc => ({
|
||||
id: doc.id,
|
||||
title: doc.meta?.title,
|
||||
}))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
"@affine/env": "workspace:*",
|
||||
"@affine/i18n": "workspace:*",
|
||||
"@affine/native": "workspace:*",
|
||||
"@blocksuite/block-std": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/blocks": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/presets": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/store": "0.16.0-canary-202407170801-6efe525",
|
||||
"@blocksuite/block-std": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/blocks": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/presets": "0.16.0-canary-202407200848-42035fe",
|
||||
"@blocksuite/store": "0.16.0-canary-202407200848-42035fe",
|
||||
"@electron-forge/cli": "^7.3.0",
|
||||
"@electron-forge/core": "^7.3.0",
|
||||
"@electron-forge/core-utils": "^7.3.0",
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
query getCopilotHistoryIds(
|
||||
$workspaceId: String!
|
||||
$docId: String
|
||||
$options: QueryChatHistoriesInput
|
||||
) {
|
||||
currentUser {
|
||||
copilot(workspaceId: $workspaceId) {
|
||||
histories(docId: $docId, options: $options) {
|
||||
sessionId
|
||||
messages {
|
||||
id
|
||||
role
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,6 +279,28 @@ query getCopilotHistories($workspaceId: String!, $docId: String, $options: Query
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getCopilotHistoryIdsQuery = {
|
||||
id: 'getCopilotHistoryIdsQuery' as const,
|
||||
operationName: 'getCopilotHistoryIds',
|
||||
definitionName: 'currentUser',
|
||||
containsFile: false,
|
||||
query: `
|
||||
query getCopilotHistoryIds($workspaceId: String!, $docId: String, $options: QueryChatHistoriesInput) {
|
||||
currentUser {
|
||||
copilot(workspaceId: $workspaceId) {
|
||||
histories(docId: $docId, options: $options) {
|
||||
sessionId
|
||||
messages {
|
||||
id
|
||||
role
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getCopilotSessionsQuery = {
|
||||
id: 'getCopilotSessionsQuery' as const,
|
||||
operationName: 'getCopilotSessions',
|
||||
|
||||
@@ -44,6 +44,11 @@ export interface BlobNotFoundDataType {
|
||||
workspaceId: Scalars['String']['output'];
|
||||
}
|
||||
|
||||
export enum ChatHistoryOrder {
|
||||
asc = 'asc',
|
||||
desc = 'desc',
|
||||
}
|
||||
|
||||
export interface ChatMessage {
|
||||
__typename?: 'ChatMessage';
|
||||
attachments: Maybe<Array<Scalars['String']['output']>>;
|
||||
@@ -847,8 +852,11 @@ export interface QueryWorkspaceArgs {
|
||||
|
||||
export interface QueryChatHistoriesInput {
|
||||
action: InputMaybe<Scalars['Boolean']['input']>;
|
||||
fork: InputMaybe<Scalars['Boolean']['input']>;
|
||||
limit: InputMaybe<Scalars['Int']['input']>;
|
||||
messageOrder: InputMaybe<ChatHistoryOrder>;
|
||||
sessionId: InputMaybe<Scalars['String']['input']>;
|
||||
sessionOrder: InputMaybe<ChatHistoryOrder>;
|
||||
skip: InputMaybe<Scalars['Int']['input']>;
|
||||
}
|
||||
|
||||
@@ -1438,6 +1446,32 @@ export type GetCopilotHistoriesQuery = {
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type GetCopilotHistoryIdsQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
docId: InputMaybe<Scalars['String']['input']>;
|
||||
options: InputMaybe<QueryChatHistoriesInput>;
|
||||
}>;
|
||||
|
||||
export type GetCopilotHistoryIdsQuery = {
|
||||
__typename?: 'Query';
|
||||
currentUser: {
|
||||
__typename?: 'UserType';
|
||||
copilot: {
|
||||
__typename?: 'Copilot';
|
||||
histories: Array<{
|
||||
__typename?: 'CopilotHistories';
|
||||
sessionId: string;
|
||||
messages: Array<{
|
||||
__typename?: 'ChatMessage';
|
||||
id: string | null;
|
||||
role: string;
|
||||
createdAt: string;
|
||||
}>;
|
||||
}>;
|
||||
};
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type GetCopilotSessionsQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
@@ -2191,6 +2225,11 @@ export type Queries =
|
||||
variables: GetCopilotHistoriesQueryVariables;
|
||||
response: GetCopilotHistoriesQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getCopilotHistoryIdsQuery';
|
||||
variables: GetCopilotHistoryIdsQueryVariables;
|
||||
response: GetCopilotHistoryIdsQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getCopilotSessionsQuery';
|
||||
variables: GetCopilotSessionsQueryVariables;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"dayjs": "^1.11.11",
|
||||
"i18next": "^23.11.1",
|
||||
"react": "^18.2.0",
|
||||
"react-i18next": "^14.1.0",
|
||||
"react-i18next": "^15.0.0",
|
||||
"undici": "^6.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1087,6 +1087,19 @@
|
||||
"com.affine.payment.upgrade-success-page.support": "If you have any questions, please contact our <1> customer support</1>.",
|
||||
"com.affine.payment.upgrade-success-page.text": "Congratulations! Your AFFiNE account has been successfully upgraded to a Pro account.",
|
||||
"com.affine.payment.upgrade-success-page.title": "Upgrade Successful!",
|
||||
"com.affine.payment.upgrade-success-notify.title": "Thanks for subscribing!",
|
||||
"com.affine.payment.upgrade-success-notify.content": "We'd like to hear more about your use case, so that we can make AFFiNE better.",
|
||||
"com.affine.payment.upgrade-success-notify.later": "Later",
|
||||
"com.affine.payment.upgrade-success-notify.ok-client": "Sure, Open In Browser",
|
||||
"com.affine.payment.upgrade-success-notify.ok-web": "Sure, Open In New Tab",
|
||||
"com.affine.payment.downgraded-notify.title": "Sorry to see you go",
|
||||
"com.affine.payment.downgraded-notify.content": "We'd like to hear more about where we fall short, so that we can make AFFiNE better.",
|
||||
"com.affine.payment.downgraded-notify.later": "Later",
|
||||
"com.affine.payment.downgraded-notify.ok-client": "Sure, Open In Browser",
|
||||
"com.affine.payment.downgraded-notify.ok-web": "Sure, Open In New Tab",
|
||||
"com.affine.payment.billing-type-form.title": "Tell Us Your Use Case",
|
||||
"com.affine.payment.billing-type-form.description": "Please tell us more about your use case, to make AFFiNE better.",
|
||||
"com.affine.payment.billing-type-form.go": "Go",
|
||||
"com.affine.peek-view-controls.close": "Close",
|
||||
"com.affine.peek-view-controls.open-doc": "Open this doc",
|
||||
"com.affine.peek-view-controls.open-doc-in-new-tab": "Open in new tab",
|
||||
|
||||
@@ -10,12 +10,20 @@ const categories = Array.from(
|
||||
await fs.readdir(join(__dirname, './stickers'))
|
||||
).filter(v => v !== '.DS_Store');
|
||||
|
||||
const naturalSort = array => {
|
||||
return array.sort(
|
||||
new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare
|
||||
);
|
||||
};
|
||||
|
||||
let i = 0;
|
||||
|
||||
for (const category of categories) {
|
||||
const stickers = Array.from(
|
||||
await fs.readdir(join(__dirname, './stickers', category, 'Cover'))
|
||||
).filter(v => v !== '.DS_Store');
|
||||
const stickers = naturalSort(
|
||||
Array.from(
|
||||
await fs.readdir(join(__dirname, './stickers', category, 'Cover'))
|
||||
).filter(v => v !== '.DS_Store')
|
||||
);
|
||||
|
||||
data[category] = {};
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="73" height="72" viewBox="0 0 73 72" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M2.64003 71.8C2.22003 71.75 1.74003 71.53 1.44003 71.22C1.12003 70.87 0.900025 70.55 0.810025 70.07C0.700025 69.48 0.81003 68.93 1.01003 68.36C1.21003 67.79 1.40003 67.24 1.66003 66.69C1.92003 66.13 2.21003 65.58 2.50003 65.04C3.05003 63.99 3.66003 62.93 4.32003 61.95C4.95003 61 5.58003 60.06 6.21003 59.12C6.62003 58.5 7.02003 57.87 7.46003 57.27C8.19003 56.27 8.91003 55.28 9.64003 54.28C10.09 53.66 10.53 53.01 11.01 52.4C12.41 50.63 13.8 48.87 15.2 47.1C15.51 46.7 15.84 46.32 16.18 45.94C17.06 44.91 17.95 43.89 18.83 42.85C19.45 42.13 20.08 41.4 20.7 40.67C21.13 40.17 21.61 39.7 22.07 39.22C23.64 37.57 25.21 35.92 26.78 34.27C27.24 33.79 27.76 33.35 28.24 32.89C29.27 31.93 30.29 30.96 31.32 30C31.92 29.44 32.51 28.88 33.11 28.32C33.65 27.81 34.25 27.35 34.81 26.87C36.47 25.47 38.13 24.07 39.79 22.66C40.41 22.13 41.09 21.66 41.74 21.17C42.84 20.32 43.94 19.48 45.04 18.63C45.48 18.3 45.9 17.95 46.36 17.64C46.68 17.43 47 17.21 47.31 17C46.77 16.1 46.24 15.2 45.71 14.31C44.7 12.61 43.57 10.98 42.62 9.24C42.06 8.21 41.57 7.06 41.37 5.9C41.18 4.81 41.17 3.55 41.7 2.54C41.93 2.11 42.23 1.68 42.63 1.38C43.03 1.08 43.43 0.88 43.91 0.74C44.42 0.58 44.99 0.570004 45.52 0.580004C46.28 0.600004 47.04 0.700005 47.79 0.800005C49.76 1.06 51.73 1.41 53.7 1.65C54.84 1.79 55.97 1.93 57.11 2.07C58.2 2.2 59.29 2.27 60.37 2.36C62.27 2.47 64.17 2.57001 66.07 2.66001C67.31 2.71001 68.58 2.76 69.8 3C70.73 3.18 71.74 3.62 72.13 4.54C72.47 5.33 72.18 6.34 71.58 6.92C71.49 7.01 71.39 7.1 71.29 7.17C71.27 7.3 71.24 7.42 71.18 7.55C70.31 9.71 69.32 11.84 68.55 14.05C68.11 15.36 67.77 16.7 67.47 18.05C67.24 19.35 67.01 20.66 66.78 21.96C66.68 22.53 66.63 23.11 66.56 23.69C66.45 24.5 66.35 25.31 66.24 26.13C65.92 28.63 65.65 31.14 65.39 33.65C65.32 34.68 65.24 35.72 65.2 36.75C65.17 37.49 65.14 38.22 65.11 38.96C65.09 39.49 65.07 40.03 65.03 40.56C65 40.94 64.97 41.33 64.88 41.7C64.79 42.07 64.67 42.43 64.54 42.79C64.23 43.74 63.34 44.25 62.36 44.03C61.92 43.93 61.48 43.77 61.16 43.44C60.85 43.12 60.64 42.78 60.43 42.39C60.21 41.99 59.95 41.61 59.73 41.21C59.31 40.42 58.89 39.62 58.48 38.82C57.49 36.91 56.5 35 55.52 33.09C53.7 29.57 51.94 26.02 50.2 22.45C50.18 22.4 50.16 22.36 50.13 22.31C49.75 21.58 49.37 20.86 49 20.13C48.94 20.17 48.88 20.21 48.82 20.25C48.41 20.53 48.02 20.82 47.62 21.13C46.57 21.94 45.51 22.75 44.45 23.56C43.65 24.18 42.84 24.79 42.04 25.41C41.57 25.77 41.12 26.18 40.67 26.56C38.97 28 37.28 29.43 35.59 30.86C33.5 32.82 31.41 34.79 29.32 36.75C29.03 37.02 28.78 37.32 28.5 37.61C27.8 38.34 27.11 39.07 26.42 39.8C25.42 40.85 24.43 41.89 23.44 42.94C22.17 44.4 20.92 45.88 19.65 47.35C19.19 47.88 18.74 48.41 18.28 48.94C17.79 49.5 17.35 50.12 16.89 50.7C15.8 52.08 14.67 53.42 13.64 54.84C12.47 56.43 11.31 58.03 10.14 59.63C9.48003 60.63 8.81003 61.62 8.15003 62.61C7.02003 64.3 5.98003 66.03 5.05003 67.84C5.06003 67.82 5.07003 67.8 5.07003 67.79C5.06003 67.81 5.05003 67.84 5.03003 67.86C5.02003 67.88 5.01003 67.9 5.00003 67.91C5.01003 67.9 5.01002 67.89 5.02002 67.87C4.90002 68.12 4.78003 68.38 4.67003 68.64C4.93003 68.9 5.12003 69.25 5.17003 69.64C5.29003 70.52 4.71003 71.38 3.86003 71.6C3.55003 71.72 3.22002 71.82 2.88002 71.82C2.79002 71.82 2.71003 71.81 2.64003 71.8ZM63.75 11.29C62.92 11.72 62.1 12.16 61.27 12.6C60.56 12.97 59.84 13.32 59.15 13.72C57.45 14.72 55.74 15.72 54.04 16.71C53.34 17.19 52.64 17.66 51.93 18.14C52.47 19.18 53.02 20.21 53.53 21.26C54.22 22.68 54.92 24.1 55.61 25.52C56.98 28.23 58.36 30.92 59.75 33.61C60.37 34.82 61 36.02 61.62 37.22C61.63 36.97 61.64 36.73 61.65 36.48C61.69 35.49 61.77 34.5 61.84 33.52C61.91 32.48 62.04 31.45 62.15 30.41C62.24 29.56 62.35 28.72 62.45 27.87C62.7 25.81 62.97 23.76 63.24 21.7C63.35 20.81 63.54 19.93 63.7 19.06C63.97 17.51 64.29 15.99 64.72 14.47C65.16 12.92 65.74 11.43 66.35 9.94C65.47 10.39 64.61 10.84 63.75 11.29ZM45.03 4.15C44.97 4.16 44.91 4.17 44.84 4.18C44.84 4.18 44.84 4.19 44.83 4.2C44.83 4.2 44.83 4.2 44.83 4.21C44.82 4.24 44.81 4.27 44.81 4.31C44.8 4.36 44.8 4.4 44.79 4.45C44.79 4.62 44.79 4.79 44.79 4.96C44.8 5.07 44.82 5.17 44.83 5.28C44.89 5.53 44.96 5.77 45.04 6.01C45.2 6.45 45.37 6.87001 45.57 7.3C46.01 8.13 46.49 8.94 46.98 9.74C47.46 10.51 47.98 11.24 48.44 12.02C48.84 12.7 49.25 13.38 49.65 14.06C49.84 14.38 50.04 14.7 50.23 15.03C50.78 14.66 51.32 14.28 51.87 13.91C52.37 13.57 52.89 13.28 53.41 12.98C55 12.05 56.58 11.07 58.21 10.21C59.93 9.3 61.65 8.39 63.37 7.5C64.12 7.11 64.86 6.73 65.6 6.34C65.68 6.3 65.76 6.25 65.85 6.21C64.43 6.14 63.01 6.08 61.59 6C59.93 5.9 58.27 5.75 56.61 5.61C55.76 5.54 54.91 5.4 54.07 5.3C53.39 5.22001 52.72 5.12 52.05 5.03C49.92 4.73 47.78 4.34 45.64 4.17C45.51 4.17 45.37 4.16001 45.25 4.16001C45.18 4.14001 45.11 4.15 45.03 4.15Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
@@ -0,0 +1,14 @@
|
||||
<svg width="82" height="80" viewBox="0 0 82 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M0.370017 65.6C-0.219983 64.84 -0.0799758 63.7 0.690024 63.12C1.14002 62.78 1.60002 62.47 2.03002 62.1C2.60002 61.62 3.18002 61.14 3.75002 60.66C6.49002 58.16 9.20002 55.64 11.86 53.06C14.64 50.36 17.4 47.65 20.2 44.99C23.25 42.1 26.29 39.21 29.36 36.34C31.93 33.94 34.48 31.52 37.09 29.17C38.6 27.81 40.1 26.45 41.61 25.08C42.97 23.86 44.37 22.69 45.75 21.49C46.96 20.44 48.22 19.42 49.46 18.4C50.07 17.9 50.71 17.44 51.33 16.95C52.54 16.02 53.77 15.09 55.23 14.57C56.14 14.25 57.16 14.59 57.55 15.52C57.91 16.37 57.51 17.52 56.61 17.84C56.35 17.93 56.1 18.02 55.86 18.13C55.55 18.3 55.25 18.49 54.96 18.68C52.84 20.16 50.87 21.84 48.88 23.49C47.27 24.82 45.71 26.2 44.15 27.58C41.15 30.29 38.17 33.01 35.21 35.75C32.65 38.13 30.09 40.51 27.55 42.92C24.4 45.91 21.26 48.91 18.14 51.93C15.39 54.59 12.64 57.25 9.86002 59.88C8.70002 60.98 7.51002 62.04 6.33002 63.12C5.75002 63.65 5.13002 64.14 4.53002 64.65C3.99002 65.1 3.43002 65.51 2.87002 65.93C2.55002 66.17 2.17002 66.29 1.79002 66.29C1.24002 66.28 0.710017 66.05 0.370017 65.6Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M5.82002 73.45C5.21002 73.45 4.60001 73.13 4.28001 72.57C3.79001 71.73 4.09 70.66 4.9 70.16C4.96 70.11 5.03001 70.0701 5.09001 70.0201C5.06001 70.05 5.03001 70.07 5.00001 70.1C5.94001 69.26 6.77001 68.29 7.62001 67.36C8.31001 66.61 9.00001 65.86 9.69001 65.11C10.87 63.82 12.07 62.5501 13.26 61.2801C16.11 58.2601 18.99 55.28 21.9 52.32C23.28 50.91 24.72 49.55 26.13 48.17C27.43 46.9 28.75 45.66 30.07 44.41C32.68 41.94 35.32 39.49 37.98 37.07C41.18 34.16 44.39 31.26 47.62 28.37C50.43 25.86 53.3 23.42 56.18 20.99C56.94 20.35 57.75 19.76 58.52 19.14C59.45 18.41 60.43 17.74 61.4 17.07C62.19 16.52 63.27 16.6 63.88 17.39C64.45 18.12 64.35 19.32 63.56 19.87C62.41 20.67 61.26 21.49 60.15 22.36C58.99 23.28 57.84 24.2 56.71 25.16C54.49 27.02 52.33 28.9401 50.15 30.8401C50.2 30.7901 50.26 30.74 50.32 30.69C44.62 35.77 38.94 40.88 33.4 46.13C31.99 47.46 30.56 48.77 29.18 50.13C27.66 51.62 26.14 53.1101 24.62 54.5901C23.24 55.9501 21.92 57.37 20.55 58.75C19.2 60.12 17.89 61.53 16.57 62.93C15.14 64.45 13.71 65.97 12.3 67.5C11.54 68.32 10.79 69.15 10.03 69.97C9.55001 70.49 9.08002 71 8.60002 71.5201C8.03002 72.14 7.43002 72.76 6.71002 73.2C6.42002 73.38 6.12002 73.45 5.82002 73.45Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M9.48001 78.11C9.48001 77.44 9.86002 76.98 10.3 76.52C10.6 76.21 10.9 75.89 11.19 75.57C13.73 72.67 16.23 69.73 18.75 66.82C19.93 65.46 21.13 64.11 22.32 62.77C23.59 61.35 24.84 59.91 26.14 58.52C28.86 55.59 31.6 52.66 34.36 49.76C37.12 46.87 39.95 44.03 42.76 41.18C45.35 38.56 47.95 35.94 50.59 33.37C53.52 30.51 56.47 27.69 59.57 25.01C60.77 23.98 62 22.99 63.2 21.97C63.93 21.35 65.11 21.56 65.68 22.29C66.29 23.08 66.09 24.15 65.36 24.77C63.84 26.07 62.29 27.33 60.77 28.64C58.02 31.13 55.3 33.66 52.66 36.28C49.9 39.03 47.14 41.77 44.4 44.54C41.68 47.29 38.95 50.04 36.29 52.85C33.6 55.68 30.89 58.49 28.29 61.4C26.04 63.92 23.79 66.44 21.56 68.97C21.51 69.02 21.47 69.08 21.42 69.13C21.46 69.09 21.49 69.05 21.53 69.01C19.96 70.83 18.4 72.64 16.82 74.45C16.15 75.22 15.5 76 14.84 76.77C14.45 77.21 14.07 77.67 13.67 78.09C13.28 78.51 12.87 78.91 12.49 79.34L12.5 79.33C12.18 79.66 11.73 79.87 11.23 79.87C10.28 79.88 9.48001 79.07 9.48001 78.11Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M72.49 25.55C72.27 25.24 72.17 24.93 72.1 24.59C72.09 24.55 72.08 24.5 72.06 24.46V24.45C72.06 24.44 72.05 24.43 72.05 24.43C71.95 24.29 71.85 24.16 71.78 24C71.75 23.93 71.73 23.86 71.71 23.78C70.1 21.43 68.46 19.11 66.81 16.8C65.16 14.5 63.32 12.35 61.51 10.18C60.51 9.07 59.46 8 58.35 7C57.87 6.58 57.39 6.16 56.9 5.75C56.58 5.48 56.24 5.21999 55.95 4.91999C55.28 4.22999 55.26 3.10999 55.95 2.41999C56.53 1.82999 57.48 1.74 58.16 2.18C58.41 1.97 58.72 1.82001 59.07 1.76001C59.13 1.75001 59.19 1.73998 59.25 1.72998C59.26 1.72998 59.27 1.72997 59.29 1.71997C60.32 1.28997 61.38 0.910028 62.47 0.650028C64.02 0.290028 65.62 0.239989 67.2 0.359989C68.65 0.469989 70.09 0.589974 71.53 0.719974C71.53 0.719974 71.54 0.719974 71.55 0.719974C71.53 0.719974 71.5 0.719974 71.48 0.719974C71.5 0.719974 71.52 0.719974 71.55 0.719974C71.56 0.719974 71.57 0.719974 71.58 0.719974C72.28 0.769974 72.98 0.809988 73.68 0.859989C74.53 0.909989 75.38 0.900018 76.23 0.890018C76.9 0.890018 77.61 0.829986 78.27 0.919986C79.25 1.04999 80.36 1.45003 80.75 2.46003C80.95 2.96003 81.03 3.42003 81.02 3.96003C81.01 4.28003 80.96 4.62001 80.89 4.94001C80.79 5.37001 80.67 5.79998 80.56 6.22998C80.34 7.07998 80.14 7.93003 79.95 8.78003C79.06 12.73 78.18 16.67 77.17 20.6C77.03 21.16 76.86 21.71 76.7 22.26C76.61 22.58 76.52 22.9 76.42 23.22C76.2 23.99 75.96 24.87 75.46 25.51C75.1 25.97 74.54 26.28 73.96 26.28C73.39 26.27 72.82 26 72.49 25.55ZM64.9 3.84998C64.38 3.89998 63.86 3.97 63.35 4.06C62.88 4.17 62.42 4.31003 61.97 4.46003C61.7 4.56003 61.43 4.67002 61.16 4.77002C61.66 5.23002 62.15 5.7 62.62 6.18C63.67 7.25 64.62 8.38002 65.58 9.52002C66.84 11.02 68.04 12.56 69.24 14.11C69.89 14.95 70.47 15.83 71.09 16.7C71.58 17.38 72.04 18.08 72.52 18.77C72.87 19.26 73.21 19.76 73.56 20.25C73.79 19.38 74.02 18.51 74.24 17.64C74.61 16.19 74.97 14.73 75.29 13.26C75.65 11.61 76.02 9.96001 76.39 8.32001C76.69 7.02001 77.03 5.71998 77.34 4.40998C76.85 4.39998 76.36 4.40998 75.88 4.40998C75.02 4.41998 74.16 4.42 73.31 4.37C72.56 4.32 71.81 4.26997 71.05 4.21997C71.07 4.21997 71.09 4.21997 71.1 4.21997C69.64 4.11997 68.17 3.96999 66.71 3.85999C66.3 3.83999 65.89 3.83002 65.48 3.83002C65.28 3.84002 65.09 3.83998 64.9 3.84998Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,38 @@
|
||||
<svg width="77" height="78" viewBox="0 0 77 78" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M61.8 14.01C61.08 13.61 60.54 12.9 60.13 12.21C59.65 11.42 59.48 10.47 59.35 9.57002C59.23 8.71002 59.28 7.83999 59.36 6.97999C59.46 5.98999 59.74 4.99999 60.17 4.09999C60.63 3.12999 61.46 2.01003 62.53 1.58003C62.54 1.49003 62.56 1.40001 62.58 1.31001C62.85 0.340007 63.81 -0.129983 64.76 0.0700169C66.04 0.350017 67.35 0.619985 68.46 1.34999C69.17 1.80999 69.69 2.46999 70.16 3.16999C70.66 3.92999 71.02 4.81001 71.24 5.69001C71.45 6.51001 71.54 7.42002 71.44 8.26002C71.33 9.18002 71.03 9.99001 70.6 10.81C69.8 12.38 68.29 13.63 66.67 14.27C65.97 14.55 65.24 14.69 64.51 14.69C63.57 14.71 62.64 14.48 61.8 14.01ZM63.65 11C63.66 11 63.67 11.01 63.68 11.02C63.73 11.04 63.78 11.06 63.83 11.09C63.91 11.11 63.99 11.14 64.07 11.16C64.16 11.18 64.25 11.19 64.34 11.2C64.43 11.2 64.51 11.2 64.59 11.2C64.67 11.19 64.75 11.18 64.83 11.16C65.02 11.12 65.21 11.07 65.39 11.01C65.48 10.97 65.56 10.94 65.64 10.9C65.81 10.81 65.98 10.71 66.14 10.61C66.31 10.49 66.48 10.36 66.64 10.22C66.74 10.13 66.84 10.03 66.93 9.93C67.07 9.77 67.19 9.61001 67.31 9.44001C67.41 9.28001 67.5 9.12003 67.59 8.96003C67.66 8.82003 67.72 8.68004 67.77 8.53004C67.81 8.41004 67.84 8.28998 67.87 8.15998C67.85 8.23998 67.84 8.32002 67.82 8.39002C67.86 8.24002 67.89 8.07999 67.9 7.91999C67.91 7.70999 67.91 7.51 67.9 7.3C67.88 7.06 67.84 6.82004 67.79 6.59004C67.76 6.47004 67.73 6.34999 67.69 6.22999C67.6 6.00999 67.51 5.79002 67.41 5.57002C67.29 5.33002 67.15 5.1 67 4.87C66.93 4.77 66.85 4.67003 66.77 4.58003C66.72 4.53003 66.67 4.47 66.62 4.43C66.57 4.39 66.52 4.35001 66.46 4.31001C66.41 4.28001 66.37 4.24998 66.32 4.21998C66.15 4.13998 65.98 4.07001 65.81 4.00001C65.56 3.93001 65.31 3.86 65.06 3.8C64.86 4.33 64.42 4.74002 63.88 4.89002C63.83 4.94002 63.77 5 63.72 5.05C63.66 5.12 63.61 5.19002 63.56 5.26002C63.5 5.37002 63.44 5.47003 63.38 5.58003C63.29 5.76003 63.22 5.95001 63.15 6.13001C63.08 6.38001 63.01 6.62 62.95 6.87C62.9 7.16 62.86 7.45 62.83 7.74C62.81 8.13 62.81 8.51998 62.83 8.90998C62.86 9.15998 62.9 9.40999 62.94 9.66999C62.98 9.85999 63.03 10.05 63.09 10.23C63.12 10.31 63.16 10.39 63.2 10.48C63.19 10.47 63.19 10.46 63.18 10.45C63.19 10.46 63.2 10.47 63.2 10.49C63.22 10.54 63.25 10.58 63.27 10.63C63.25 10.59 63.23 10.56 63.22 10.52C63.23 10.54 63.24 10.55 63.26 10.57C63.25 10.55 63.23 10.53 63.22 10.51C63.21 10.48 63.19 10.46 63.18 10.43C63.22 10.48 63.25 10.54 63.28 10.59L63.29 10.6C63.29 10.61 63.29 10.61 63.3 10.62C63.35 10.69 63.41 10.76 63.46 10.83C63.51 10.88 63.56 10.93 63.61 10.98C63.6 10.97 63.58 10.96 63.57 10.94C63.59 10.96 63.62 10.98 63.65 11Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M46.6 16.55C44.85 16.43 43.01 15.71 41.85 14.36C40.62 12.94 40.1 11.05 40.31 9.19003C40.52 7.31003 41.22 5.39002 42.53 3.99002C43.03 3.45002 43.65 2.90004 44.35 2.58004C44.41 2.42004 44.49 2.27004 44.6 2.14004C45.21 1.35004 46.29 1.28003 47.08 1.82003C47.53 2.13003 47.96 2.45 48.38 2.79C49.17 3.41 49.86 4.15 50.51 4.91C51.15 5.66 51.7 6.5 52.19 7.35C52.65 8.13 52.97 9.01005 53.11 9.90005C53.25 10.81 53.23 11.68 52.99 12.56C52.75 13.41 52.27 14.14 51.69 14.79C51.12 15.43 50.3 15.88 49.51 16.18C48.78 16.45 47.98 16.56 47.2 16.56C46.99 16.57 46.79 16.56 46.6 16.55ZM45.84 5.80001C45.77 5.84001 45.7 5.88001 45.63 5.92001C45.56 5.97001 45.49 6.03004 45.42 6.08004C45.31 6.18004 45.21 6.29005 45.1 6.40005C45 6.51005 44.91 6.63002 44.82 6.75002C44.7 6.94002 44.58 7.14005 44.47 7.34005C44.35 7.61005 44.23 7.88005 44.13 8.15005C44.06 8.40005 43.99 8.65 43.93 8.91C43.88 9.14 43.85 9.38001 43.82 9.61001C43.81 9.81001 43.81 10.01 43.82 10.22C43.84 10.42 43.87 10.63 43.9 10.83C43.93 10.95 43.96 11.06 44 11.18C44.03 11.26 44.07 11.34 44.1 11.42C44.15 11.52 44.21 11.62 44.27 11.72C44.34 11.83 44.43 11.9301 44.51 12.0301C44.58 12.1001 44.64 12.16 44.71 12.23C44.77 12.28 44.83 12.32 44.89 12.37C45 12.44 45.11 12.51 45.23 12.57C45.41 12.66 45.6 12.74 45.78 12.81C45.97 12.87 46.16 12.92 46.35 12.97C46.49 12.99 46.63 13.01 46.77 13.02C46.98 13.03 47.19 13.0301 47.39 13.0301C47.59 13.0101 47.78 12.99 47.98 12.96C48.08 12.94 48.18 12.91 48.28 12.87C48.37 12.83 48.47 12.79 48.56 12.75C48.64 12.71 48.72 12.66 48.79 12.61C48.88 12.55 48.97 12.48 49.05 12.41C49.1 12.36 49.15 12.32 49.2 12.27C49.24 12.22 49.28 12.16 49.32 12.11C49.37 12.03 49.41 11.95 49.46 11.88C49.5 11.79 49.54 11.69 49.58 11.6C49.6 11.52 49.62 11.44 49.64 11.37C49.65 11.3 49.66 11.24 49.67 11.18C49.67 11.07 49.67 10.96 49.67 10.85C49.65 10.73 49.64 10.6 49.62 10.48C49.57 10.27 49.51 10.06 49.46 9.85C49.39 9.67 49.31 9.49002 49.23 9.31002C48.98 8.85002 48.69 8.42002 48.41 7.99002C48.15 7.62002 47.87 7.27002 47.59 6.93002C47.27 6.58002 46.95 6.24001 46.6 5.92001C46.51 5.84001 46.42 5.77003 46.33 5.69003C46.16 5.74003 46 5.78001 45.84 5.80001Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M26.01 18.76C24.4 18.68 22.99 17.76 22.03 16.51C20.99 15.15 20.59 13.35 20.58 11.67C20.57 9.94999 21.17 8.27001 22.26 6.94001C22.76 6.33001 23.4 5.85 24.05 5.43C24.43 5.19 24.85 5.00999 25.28 4.85999C25.52 4.76999 25.79 4.68003 26.05 4.65003C26.22 4.64003 26.38 4.64999 26.55 4.66999C26.63 4.39999 26.77 4.15001 26.99 3.94001C27.65 3.28001 28.84 3.23001 29.49 3.94001C30.67 5.24001 32.02 6.48998 32.78 8.09998C33.51 9.64998 33.53 11.41 33.06 13.04C32.62 14.55 31.72 16.03 30.54 17.07C29.91 17.62 29.22 18.06 28.45 18.39C27.8 18.66 27.08 18.77 26.38 18.77C26.24 18.77 26.13 18.77 26.01 18.76ZM26.57 8.15998C26.53 8.16998 26.5 8.18001 26.47 8.19001C26.38 8.23001 26.29 8.25999 26.19 8.29999C26.02 8.38999 25.86 8.48002 25.7 8.58002C25.54 8.70002 25.4 8.81001 25.25 8.94001C25.16 9.03001 25.07 9.12003 24.98 9.21003C24.91 9.30003 24.84 9.39 24.77 9.49C24.7 9.59999 24.63 9.72002 24.57 9.83002C24.48 10.02 24.4 10.21 24.32 10.4C24.29 10.51 24.26 10.61 24.23 10.72C24.19 10.97 24.15 11.21 24.13 11.46C24.12 11.69 24.12 11.91 24.13 12.13C24.16 12.38 24.19 12.63 24.24 12.88C24.27 13.02 24.31 13.15 24.35 13.28C24.42 13.49 24.51 13.69 24.6 13.89C24.68 14.05 24.77 14.2 24.87 14.35C24.92 14.42 24.96 14.48 25.01 14.55C25.06 14.6 25.1 14.64 25.15 14.69C25.15 14.69 25.16 14.7 25.17 14.7C25.17 14.71 25.18 14.72 25.19 14.72C25.28 14.79 25.37 14.86 25.47 14.93C25.54 14.98 25.62 15.02 25.7 15.06C25.75 15.09 25.81 15.11 25.86 15.13C25.91 15.15 25.95 15.16 26 15.17C26.09 15.18 26.17 15.19 26.25 15.2C26.34 15.2 26.43 15.2 26.53 15.2C26.64 15.19 26.74 15.18 26.85 15.16C26.93 15.14 27.01 15.12 27.08 15.1C27.15 15.07 27.21 15.04 27.28 15.01C27.45 14.92 27.61 14.83 27.76 14.73C27.92 14.61 28.08 14.48 28.23 14.35C28.32 14.26 28.41 14.17 28.49 14.08C28.62 13.92 28.74 13.77 28.86 13.61C29.02 13.37 29.16 13.12 29.3 12.86C29.41 12.63 29.5 12.41 29.59 12.17C29.65 11.98 29.71 11.78 29.76 11.59C29.79 11.41 29.81 11.23 29.83 11.05C29.83 10.91 29.83 10.78 29.83 10.64C29.82 10.49 29.79 10.34 29.77 10.19C29.74 10.06 29.71 9.93 29.66 9.81C29.63 9.74 29.61 9.66999 29.57 9.60999C29.46 9.41999 29.35 9.22999 29.23 9.04999C29.23 9.04999 29.24 9.06001 29.24 9.07001C29.02 8.75001 28.79 8.44998 28.55 8.15998C28.29 7.86998 28.03 7.59 27.77 7.31C27.53 7.77 27.09 8.09998 26.57 8.15998Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M5.49 21.01C5.06 20.95 4.62 20.87 4.21 20.71C3.4 20.39 2.71 19.88 2.09 19.26C1.46 18.63 1.04001 17.81 0.690009 17C0.280009 16.03 0.0900051 15 0.0300051 13.95C-0.0899949 12.06 0.630001 10.22 1.87 8.82001C2.69 7.89001 3.76001 6.96999 4.97001 6.54999C4.92001 6.01999 5.10002 5.46003 5.48002 5.09003C5.81002 4.76003 6.26002 4.57001 6.73002 4.57001C7.22002 4.57001 7.62002 4.77003 7.98002 5.09003C8.74002 5.76003 9.44 6.47998 10.12 7.22998C10.75 7.91998 11.32 8.74998 11.71 9.59998C12.14 10.52 12.37 11.5 12.46 12.51C12.63 14.4 12.12 16.3 11.17 17.93C10.23 19.54 8.64001 20.67 6.82001 20.99C6.61001 21.03 6.38 21.04 6.15 21.04C5.93 21.06 5.7 21.04 5.49 21.01ZM4.82001 16.99C4.91001 17.06 4.98999 17.13 5.07999 17.2C5.16999 17.26 5.26001 17.31 5.35001 17.36C5.40001 17.38 5.44 17.4 5.49 17.41C5.55 17.43 5.62001 17.45 5.69001 17.46C5.78001 17.48 5.87001 17.49 5.97001 17.5C6.07001 17.5 6.17 17.5 6.27 17.5C6.33 17.5 6.39001 17.49 6.44001 17.48C6.50001 17.46 6.56001 17.45 6.63001 17.43C6.72001 17.39 6.82001 17.36 6.91001 17.31C7.00001 17.26 7.09 17.21 7.18 17.15C7.32 17.05 7.45 16.95 7.59 16.84C7.66 16.77 7.72001 16.71 7.78 16.64C7.87001 16.54 7.95001 16.43 8.03001 16.32C8.15001 16.12 8.27001 15.93 8.38001 15.73C8.47001 15.52 8.56 15.32 8.65 15.11C8.74 14.84 8.81 14.58 8.87 14.31C8.91 14.06 8.94001 13.82 8.97001 13.57C8.98001 13.33 8.98001 13.09 8.97001 12.85C8.94001 12.62 8.91 12.39 8.87 12.15C8.81 11.9 8.75002 11.66 8.67002 11.42C8.63002 11.32 8.58999 11.23 8.54999 11.13C8.38999 10.83 8.21001 10.55 8.03001 10.27C7.87001 10.04 7.71 9.83 7.53 9.62C7.47001 9.55 7.41001 9.48999 7.35001 9.42999C7.07001 9.65999 6.72001 9.80999 6.35001 9.85999C6.37001 9.85999 6.40002 9.85999 6.42002 9.85999C6.38002 9.85999 6.33999 9.87 6.29999 9.87C6.27999 9.87 6.26 9.88001 6.24 9.89001C6.07 9.96001 5.91001 10.03 5.75001 10.12C5.82001 10.09 5.89002 10.05 5.95002 10.02C5.85002 10.07 5.75 10.13 5.65 10.2C5.45 10.34 5.26001 10.49 5.07001 10.65C4.90001 10.81 4.73 10.98 4.56 11.15C4.43 11.3 4.31002 11.45 4.20002 11.61C4.11002 11.75 4.02002 11.9 3.95002 12.04C3.87002 12.21 3.8 12.37 3.74 12.55C3.71 12.65 3.69001 12.75 3.66001 12.85C3.63001 12.99 3.61001 13.14 3.60001 13.28C3.59001 13.55 3.58001 13.81 3.60001 14.07C3.63001 14.3 3.66002 14.52 3.70002 14.75C3.76002 14.97 3.82002 15.19 3.89002 15.41C3.97002 15.63 4.07001 15.85 4.16001 16.06C4.26001 16.25 4.37002 16.43 4.48002 16.61C4.57002 16.72 4.66002 16.84 4.76002 16.94C4.71002 16.89 4.65999 16.83 4.60999 16.77C4.66999 16.85 4.74001 16.92 4.82001 16.99Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M64.15 33.69C62.61 32.22 62.08 30.15 62.06 28.08C62.04 25.98 62.66 23.8 63.91 22.12C64.49 21.33 65.28 20.73 66.19 20.38C66.6 20.22 67.0601 20.13 67.51 20.13C67.55 20.08 67.6 20.03 67.65 19.98C68.33 19.3 69.48 19.29 70.15 19.98C71.34 21.19 72.54 22.43 73.4 23.91C73.92 24.82 74.29 25.78 74.47 26.8C74.67 27.88 74.5 28.98 74.1 30C73.73 30.94 73.1101 31.8 72.4201 32.54C71.6501 33.36 70.78 34 69.77 34.48C69.08 34.8 68.3 34.97 67.52 34.97C66.28 34.96 65.04 34.54 64.15 33.69ZM67.02 23.94C66.96 24 66.9 24.06 66.84 24.12C66.75 24.23 66.66 24.35 66.57 24.46C66.48 24.61 66.39 24.76 66.3 24.92C66.2 25.13 66.12 25.34 66.03 25.56C65.92 25.9 65.83 26.25 65.75 26.6C65.69 26.94 65.64 27.28 65.61 27.62C65.6 27.93 65.6 28.24 65.61 28.56C65.64 28.86 65.67 29.15 65.72 29.44C65.77 29.66 65.84 29.88 65.91 30.1C65.95 30.19 65.99 30.29 66.03 30.39C66.09 30.5 66.16 30.62 66.23 30.73C66.2801 30.8 66.34 30.88 66.4 30.95C66.45 31 66.49 31.0501 66.54 31.0901C66.58 31.1201 66.62 31.15 66.66 31.18C66.7 31.2 66.74 31.23 66.78 31.25C66.85 31.28 66.9201 31.3001 66.98 31.3401C67.05 31.3601 67.11 31.38 67.18 31.39C67.25 31.4 67.3201 31.41 67.3901 31.42C67.4401 31.42 67.48 31.42 67.52 31.42C67.62 31.41 67.72 31.4 67.82 31.38C67.96 31.35 68.11 31.31 68.25 31.26C68.33 31.23 68.41 31.19 68.49 31.15C68.67 31.05 68.83 30.9501 69 30.8401C69.12 30.7501 69.23 30.67 69.34 30.57C69.52 30.41 69.68 30.24 69.84 30.07C70.04 29.84 70.23 29.6001 70.41 29.3401C70.51 29.1801 70.6 29.02 70.69 28.85C70.77 28.7 70.8301 28.54 70.8901 28.38C70.91 28.33 70.92 28.27 70.93 28.22C70.94 28.14 70.95 28.05 70.96 27.97C70.96 27.87 70.96 27.77 70.96 27.68C70.94 27.48 70.9201 27.2901 70.8901 27.0901C70.8701 26.9901 70.84 26.89 70.81 26.8C70.71 26.54 70.61 26.29 70.49 26.05C70.34 25.75 70.17 25.46 69.99 25.17C69.75 24.83 69.5 24.5 69.24 24.19C69.15 24.08 69.05 23.98 68.9501 23.87C68.94 23.88 68.9301 23.89 68.9201 23.89C68.34 24.25 67.62 24.19 67.08 23.85C67.08 23.89 67.05 23.91 67.02 23.94Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M66.27 57.38C64.31 56.67 62.94 55.02 62.33 53.06C62.01 52.01 61.99 50.8799 62.06 49.7899C62.14 48.6299 62.52 47.43 63.04 46.4C63.99 44.52 65.55 42.9699 67.61 42.4099C68.52 42.1599 69.51 42.21 70.33 42.69C70.94 43.05 71.3 43.74 71.3 44.44C71.3 44.52 71.3 44.6 71.28 44.67C72 45.08 72.65 45.6099 73.26 46.1599C74.12 46.9499 74.82 47.86 75.39 48.89C75.91 49.81 76.22 50.87 76.11 51.93C76.02 52.86 75.73 53.82 75.15 54.57C74.49 55.42 73.67 56.09 72.74 56.62C71.74 57.19 70.62 57.5199 69.49 57.7199C69.18 57.7699 68.87 57.8 68.54 57.8C67.79 57.8 66.99 57.64 66.27 57.38ZM67.88 54.17C68.07 54.21 68.26 54.23 68.46 54.25C68.55 54.25 68.64 54.25 68.73 54.25C68.89 54.23 69.04 54.21 69.2 54.19C69.55 54.11 69.89 54.01 70.24 53.9C70.44 53.82 70.63 53.74 70.83 53.65C71.03 53.54 71.21 53.44 71.4 53.32C71.56 53.21 71.71 53.0899 71.86 52.9699C72 52.8499 72.13 52.72 72.25 52.58C72.29 52.53 72.34 52.47 72.38 52.42C72.4 52.39 72.42 52.36 72.43 52.33C72.46 52.26 72.49 52.19 72.52 52.12C72.54 52.03 72.57 51.95 72.59 51.86C72.61 51.79 72.61 51.71 72.62 51.64C72.62 51.57 72.62 51.5 72.62 51.43C72.62 51.39 72.61 51.35 72.6 51.31C72.58 51.24 72.56 51.16 72.54 51.08C72.51 51 72.47 50.92 72.44 50.84C72.28 50.53 72.11 50.24 71.92 49.95C71.8 49.78 71.67 49.62 71.54 49.46C71.24 49.13 70.92 48.82 70.59 48.51C70.37 48.33 70.15 48.16 69.92 47.99C69.74 47.88 69.56 47.77 69.38 47.67C68.73 47.38 68.06 47.11 67.39 46.87C67.28 46.83 67.19 46.7799 67.1 46.7299C67.05 46.7799 67 46.84 66.95 46.89C66.81 47.07 66.67 47.25 66.54 47.43C66.42 47.64 66.3 47.84 66.18 48.05C66.08 48.28 65.98 48.51 65.89 48.75C65.81 49 65.74 49.25 65.68 49.51C65.63 49.81 65.59 50.11 65.56 50.42C65.55 50.65 65.56 50.8699 65.56 51.0999C65.58 51.3299 65.61 51.55 65.65 51.78C65.69 51.97 65.74 52.1599 65.8 52.3499C65.83 52.4399 65.87 52.52 65.91 52.61C65.99 52.77 66.08 52.91 66.18 53.07C66.25 53.18 66.34 53.28 66.42 53.38C66.51 53.47 66.6 53.56 66.69 53.65C66.76 53.71 66.82 53.76 66.9 53.81C66.97 53.86 67.05 53.9 67.12 53.94C67.29 54.02 67.46 54.09 67.64 54.14C67.57 54.11 67.5 54.09 67.42 54.06C67.58 54.09 67.73 54.13 67.88 54.17Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M66.4 77.21C65.4 76.86 64.6 76.19 63.94 75.37C63.26 74.51 62.95 73.38 62.8 72.32C62.64 71.15 62.84 69.91 63.19 68.79C63.49 67.82 63.98 66.92 64.6 66.12C64.92 65.71 65.31 65.35 65.71 65.03C65.73 65.02 65.74 65.01 65.76 64.99C65.6 64.69 65.53 64.33 65.58 63.96C65.71 63.01 66.62 62.3 67.58 62.44C70.95 62.95 74.95 64.28 76.16 67.82C76.3 68.23 76.35 68.71 76.35 69.14C76.35 69.71 76.28 70.23 76.16 70.78C75.91 71.91 75.27 72.99 74.61 73.93C73.36 75.73 71.34 77.06 69.18 77.44C68.89 77.49 68.59 77.51 68.29 77.51C67.65 77.53 66.99 77.42 66.4 77.21ZM66.89 73.39C66.94 73.44 66.99 73.5 67.05 73.55C67.13 73.62 67.21 73.68 67.29 73.74C67.34 73.77 67.4 73.81 67.46 73.84C67.5 73.86 67.54 73.88 67.58 73.89C67.64 73.91 67.7 73.92 67.76 73.94C67.85 73.96 67.94 73.97 68.03 73.98C68.2 73.98 68.37 73.98 68.54 73.98C68.65 73.97 68.75 73.95 68.86 73.93C68.95 73.91 69.05 73.88 69.14 73.86C69.35 73.78 69.56 73.69 69.76 73.59C69.94 73.49 70.13 73.39 70.3 73.28C70.49 73.14 70.68 72.99 70.85 72.85C71.05 72.66 71.24 72.47 71.42 72.27C71.58 72.07 71.73 71.88 71.88 71.67C72.03 71.43 72.17 71.19 72.3 70.95C72.43 70.68 72.55 70.4 72.66 70.11C72.7 70 72.73 69.88 72.76 69.76C72.77 69.67 72.78 69.58 72.79 69.49C72.79 69.54 72.79 69.59 72.78 69.64V69.65C72.78 69.67 72.78 69.68 72.78 69.69C72.78 69.67 72.78 69.66 72.79 69.64C72.8 69.48 72.8 69.32 72.79 69.16C72.8 69.24 72.8 69.32 72.81 69.4C72.81 69.22 72.79 69.04 72.76 68.86C72.74 68.79 72.72 68.71 72.69 68.64C72.69 68.64 72.7 68.65 72.7 68.66C72.7 68.66 72.69 68.65 72.69 68.64C72.68 68.6 72.66 68.56 72.64 68.52C72.65 68.56 72.67 68.59 72.68 68.63C72.67 68.62 72.66 68.61 72.66 68.6C72.67 68.61 72.68 68.62 72.68 68.63C72.69 68.65 72.69 68.67 72.7 68.68C72.7 68.69 72.71 68.69 72.71 68.7C72.71 68.7 72.71 68.69 72.7 68.69C72.71 68.71 72.71 68.72 72.72 68.74C72.71 68.71 72.7 68.68 72.68 68.65C72.65 68.6 72.62 68.54 72.59 68.49C72.54 68.42 72.48 68.35 72.43 68.29C72.25 68.1 72.07 67.91 71.88 67.74C71.78 67.66 71.68 67.58 71.58 67.51C71.25 67.3 70.92 67.1 70.57 66.92C70.36 66.83 70.14 66.74 69.93 66.66C69.91 66.79 69.89 66.92 69.85 67.05C69.59 67.98 68.61 68.54 67.67 68.28C67.6 68.26 67.53 68.24 67.46 68.21C67.34 68.35 67.23 68.49 67.13 68.64C67.03 68.8 66.94 68.96 66.85 69.12C66.75 69.33 66.66 69.56 66.57 69.78C66.5 70.01 66.44 70.24 66.38 70.47C66.34 70.73 66.3 70.99 66.28 71.26C66.27 71.4 66.27 71.55 66.28 71.69C66.3 71.9 66.33 72.1 66.36 72.3C66.39 72.44 66.43 72.58 66.47 72.71C66.52 72.83 66.57 72.95 66.62 73.06C66.66 73.14 66.71 73.22 66.76 73.29C66.76 73.29 66.76 73.29 66.77 73.29C66.79 73.33 66.82 73.37 66.84 73.4C66.82 73.37 66.8 73.34 66.78 73.3C66.76 73.27 66.74 73.24 66.72 73.21C66.79 73.27 66.85 73.33 66.89 73.39Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M27.6 36.55C26.72 36.45 25.92 36.01 25.22 35.51C24.51 35.01 24.06 34.22 23.7 33.45C23.3 32.58 23.21 31.61 23.19 30.67C23.17 29.7 23.38 28.7 23.7 27.79C24.29 26.15 25.38 24.5999 27.07 23.9699C27.82 23.6799 28.61 23.68 29.38 23.86C29.7 23.93 30.05 24.1 30.33 24.32C30.6 24.34 30.86 24.41 31.11 24.53C33.41 25.7 36.77 27.36 36.09 30.48C35.9 31.37 35.43 32.2299 34.89 32.9699C34.34 33.7199 33.7 34.3799 32.98 34.9699C31.69 36.0199 30.03 36.59 28.37 36.59C28.12 36.59 27.86 36.58 27.6 36.55ZM28.08 27.39C28.02 27.44 27.96 27.49 27.9 27.54C27.85 27.59 27.79 27.65 27.74 27.7C27.67 27.78 27.61 27.86 27.54 27.94C27.44 28.11 27.34 28.27 27.25 28.44C27.17 28.62 27.09 28.8 27.03 28.98C26.96 29.22 26.89 29.46 26.83 29.7C26.79 29.94 26.76 30.1799 26.74 30.4099C26.74 30.6599 26.74 30.89 26.75 31.14C26.77 31.3 26.79 31.45 26.82 31.61C26.84 31.7 26.86 31.79 26.89 31.88C26.93 32 26.98 32.11 27.04 32.23C27.08 32.31 27.13 32.38 27.17 32.46C27.2 32.5 27.23 32.54 27.26 32.58C27.29 32.61 27.31 32.63 27.34 32.67C27.39 32.71 27.43 32.74 27.48 32.78C27.54 32.82 27.6 32.86 27.68 32.9C27.74 32.93 27.8 32.95 27.87 32.98C27.93 33 27.99 33.02 28.05 33.03C28.13 33.05 28.21 33.05 28.28 33.06C28.39 33.06 28.5 33.06 28.61 33.06C28.8 33.04 28.99 33.01 29.18 32.98C29.28 32.96 29.38 32.93 29.48 32.89C29.69 32.81 29.91 32.72 30.11 32.62C30.29 32.52 30.47 32.41 30.65 32.3C30.76 32.22 30.87 32.14 30.97 32.05C31.22 31.83 31.45 31.5899 31.68 31.3499C31.82 31.1899 31.94 31.03 32.07 30.86C32.23 30.61 32.37 30.37 32.51 30.11C32.55 30.02 32.6 29.92 32.63 29.82C32.63 29.8 32.64 29.78 32.64 29.75C32.64 29.73 32.64 29.71 32.64 29.69C32.63 29.68 32.62 29.6699 32.62 29.6599C32.5 29.5399 32.38 29.41 32.25 29.29C32.18 29.23 32.1 29.18 32.02 29.12C31.16 28.55 30.25 28.05 29.33 27.58C29.31 27.57 29.3 27.56 29.28 27.56C28.94 27.55 28.61 27.45 28.33 27.27C28.32 27.27 28.31 27.27 28.31 27.28C28.29 27.29 28.26 27.3 28.24 27.31C28.18 27.34 28.13 27.37 28.08 27.39Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M47.6 36.18C46.76 36.05 45.89 35.76 45.21 35.23C44.55 34.71 44.05 34.06 43.69 33.3C42.85 31.54 42.61 29.46 43.05 27.56C43.25 26.7 43.57 25.81 44.12 25.1C44.67 24.39 45.33 23.89 46.18 23.58C46.46 23.48 46.77 23.41 47.1 23.38C47.55 22.68 48.49 22.33 49.28 22.69C49.77 22.92 50.25 23.15 50.74 23.39C51.07 23.55 51.41 23.69 51.74 23.87C52.14 24.09 52.51 24.35 52.88 24.62C54.37 25.74 55.21 27.69 55 29.55C54.8 31.39 53.93 33.03 52.59 34.3C51.95 34.91 51.2 35.38 50.38 35.72C49.71 36.01 48.91 36.22 48.15 36.22C47.96 36.22 47.78 36.21 47.6 36.18ZM47.63 32.56C47.63 32.57 47.64 32.57 47.63 32.56C47.72 32.6 47.81 32.62 47.9 32.64C47.95 32.65 48 32.66 48.05 32.66C48.09 32.66 48.13 32.66 48.17 32.66C48.27 32.65 48.36 32.64 48.46 32.62C48.57 32.59 48.67 32.57 48.78 32.53C48.99 32.46 49.18 32.37 49.38 32.28C49.47 32.23 49.57 32.17 49.66 32.11C49.82 31.99 49.96 31.88 50.11 31.75C50.26 31.61 50.4 31.46 50.54 31.31C50.62 31.21 50.7 31.11 50.78 31.01C50.89 30.84 50.99 30.66 51.1 30.48C51.17 30.32 51.24 30.16 51.3 30C51.35 29.84 51.39 29.68 51.43 29.52C51.45 29.4 51.47 29.27 51.48 29.14C51.48 29.05 51.48 28.97 51.48 28.88C51.47 28.79 51.46 28.71 51.45 28.62C51.42 28.51 51.39 28.39 51.35 28.28C51.31 28.2 51.28 28.12 51.25 28.04C51.21 27.97 51.18 27.91 51.14 27.85C51.11 27.81 51.08 27.77 51.05 27.73C51.01 27.68 50.96 27.63 50.91 27.59C50.71 27.43 50.51 27.27 50.3 27.12C50.23 27.08 50.15 27.03 50.07 26.99C50 26.95 49.92 26.92 49.85 26.88C49.77 26.95 49.68 27.02 49.58 27.08C48.93 27.46 48.15 27.37 47.59 26.93C47.58 26.93 47.57 26.93 47.57 26.92C47.54 26.92 47.52 26.91 47.5 26.91C47.46 26.91 47.42 26.91 47.38 26.91C47.37 26.91 47.36 26.91 47.35 26.92C47.36 26.92 47.36 26.92 47.37 26.91C47.33 26.93 47.29 26.95 47.25 26.96C47.22 26.98 47.2 27 47.17 27.01C47.15 27.03 47.13 27.04 47.11 27.06C47.1 27.08 47.08 27.09 47.07 27.11C47.03 27.16 46.99 27.21 46.96 27.25C46.9 27.34 46.85 27.44 46.8 27.53C46.75 27.64 46.71 27.74 46.66 27.85C46.61 28.03 46.55 28.2 46.51 28.38C46.47 28.61 46.44 28.84 46.42 29.07C46.41 29.36 46.41 29.64 46.42 29.93C46.44 30.17 46.47 30.41 46.51 30.64C46.56 30.85 46.62 31.05 46.68 31.25C46.76 31.45 46.85 31.66 46.94 31.86C46.99 31.96 47.05 32.05 47.11 32.15C47.15 32.19 47.18 32.24 47.21 32.27C47.23 32.29 47.25 32.31 47.27 32.33C47.3 32.35 47.33 32.38 47.36 32.4C47.42 32.44 47.48 32.47 47.54 32.5C47.61 32.53 47.68 32.56 47.75 32.59C47.71 32.58 47.68 32.57 47.64 32.55C47.63 32.55 47.62 32.54 47.62 32.54C47.63 32.54 47.63 32.55 47.64 32.55C47.6 32.54 47.57 32.53 47.53 32.51C47.55 32.53 47.59 32.55 47.63 32.56Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M49.73 56.68C48.8 56.34 47.94 55.64 47.28 54.91C46.62 54.19 46.12 53.35 45.71 52.47C45.25 51.5 45.07 50.42 45.03 49.36C44.99 48.42 45.24 47.44 45.62 46.59C46.01 45.7001 46.69 44.99 47.49 44.46C47.83 44.23 48.26 44.1 48.65 43.99C49.11 43.86 49.64 43.84 50.11 43.89C50.31 43.91 50.49 43.95 50.68 44C50.7 44 50.73 43.99 50.75 43.98C51.3 43.88 51.86 43.78 52.42 43.75C52.89 43.72 53.35 43.7401 53.81 43.84C54.31 43.94 54.76 44.15 55.21 44.4C55.99 44.84 56.63 45.5 57.21 46.18C57.9 46.99 58.35 47.93 58.68 48.94C58.98 49.84 58.97 50.82 58.8 51.74C58.61 52.74 58.16 53.62 57.57 54.45C56.98 55.28 56.1 55.95 55.19 56.41C54.33 56.84 53.36 57.12 52.4 57.14C52.35 57.14 52.31 57.14 52.27 57.14C51.38 57.14 50.56 56.99 49.73 56.68ZM48.57 49.13C48.56 49.28 48.57 49.43 48.57 49.59C48.59 49.7401 48.61 49.8801 48.63 50.0301C48.68 50.2601 48.74 50.48 48.81 50.7C48.89 50.91 48.97 51.11 49.07 51.31C49.2 51.55 49.34 51.79 49.49 52.02C49.61 52.18 49.73 52.34 49.86 52.5C49.98 52.62 50.1 52.75 50.22 52.86C50.34 52.96 50.45 53.05 50.58 53.14C50.7 53.22 50.83 53.3 50.96 53.37C51.05 53.41 51.14 53.44 51.23 53.48C51.32 53.51 51.41 53.53 51.5 53.55C51.64 53.58 51.79 53.6 51.93 53.61C52.05 53.61 52.16 53.61 52.28 53.61C52.46 53.59 52.64 53.57 52.82 53.54C52.93 53.51 53.04 53.48 53.14 53.45C53.26 53.4 53.39 53.35 53.52 53.29C53.7 53.2 53.88 53.09 54.05 52.98C54.14 52.91 54.22 52.8501 54.3 52.7801C54.42 52.6701 54.54 52.55 54.65 52.43C54.72 52.34 54.78 52.25 54.85 52.16C54.92 52.05 54.99 51.93 55.05 51.82C55.11 51.7 55.16 51.57 55.21 51.44C55.25 51.32 55.28 51.2 55.31 51.07C55.33 50.95 55.35 50.84 55.36 50.71C55.36 50.62 55.36 50.53 55.36 50.43C55.35 50.34 55.34 50.26 55.32 50.17C55.29 50.04 55.25 49.9 55.21 49.77C55.15 49.6 55.08 49.44 55.01 49.27C54.92 49.1 54.82 48.93 54.72 48.77C54.58 48.58 54.43 48.4 54.29 48.22C54.15 48.06 54 47.92 53.84 47.77C53.73 47.68 53.62 47.59 53.5 47.52C53.41 47.47 53.33 47.41 53.24 47.36C53.19 47.34 53.13 47.31 53.08 47.29C52.96 47.27 52.84 47.26 52.72 47.25C52.8 47.26 52.88 47.26 52.96 47.27C52.78 47.26 52.59 47.2601 52.41 47.2801C52.49 47.2801 52.57 47.27 52.65 47.26C52.17 47.33 51.69 47.39 51.22 47.48C51.19 47.49 51.16 47.49 51.13 47.5C50.68 47.66 50.2 47.62 49.78 47.42C49.77 47.42 49.76 47.41 49.75 47.4C49.74 47.4 49.73 47.4 49.71 47.4C49.67 47.4 49.62 47.4 49.58 47.4C49.56 47.4 49.54 47.41 49.52 47.41C49.49 47.42 49.47 47.43 49.44 47.43C49.39 47.45 49.35 47.47 49.31 47.48C49.33 47.47 49.34 47.46 49.36 47.46C49.36 47.46 49.35 47.46 49.34 47.46C49.31 47.48 49.28 47.5 49.25 47.51C49.23 47.53 49.21 47.55 49.18 47.57C49.15 47.6 49.12 47.63 49.09 47.67C49.05 47.72 49 47.78 48.96 47.84C48.98 47.8101 49 47.78 49.02 47.75C49.02 47.75 49.02 47.75 49.01 47.75C48.95 47.85 48.89 47.95 48.83 48.05C48.79 48.13 48.76 48.22 48.72 48.3C48.66 48.5 48.61 48.7 48.58 48.9C48.6 48.82 48.61 48.74 48.63 48.67C48.61 48.83 48.58 48.97 48.57 49.13Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M29.59 56C28.85 55.95 28.09 55.6 27.47 55.21C26.79 54.79 26.26 54.16 25.93 53.43C25.18 51.82 25.22 49.99 25.61 48.29C25.98 46.71 26.75 45.06 28.23 44.25C28.91 43.88 29.63 43.8 30.39 43.89C30.68 43.93 30.98 44.03 31.25 44.17C31.49 44.16 31.73 44.21 31.96 44.31C33.11 44.83 34.28 45.35 35.28 46.14C36.51 47.11 37.1 48.84 36.92 50.37C36.83 51.14 36.62 51.9 36.25 52.58C35.82 53.37 35.26 54.01 34.56 54.57C33.33 55.57 31.73 56.01 30.17 56.01C29.98 56.02 29.79 56.01 29.59 56ZM29.78 47.47C29.74 47.52 29.7 47.57 29.66 47.62C29.58 47.74 29.51 47.87 29.44 48C29.36 48.17 29.29 48.34 29.23 48.51C29.17 48.71 29.11 48.91 29.06 49.12C28.99 49.51 28.93 49.9 28.89 50.3C28.88 50.55 28.87 50.8 28.88 51.04C28.89 51.14 28.9 51.24 28.92 51.33C28.95 51.44 28.98 51.55 29.01 51.66C29.05 51.75 29.08 51.84 29.12 51.93C29.15 51.98 29.18 52.03 29.21 52.08C29.22 52.09 29.23 52.11 29.24 52.12C29.25 52.14 29.27 52.15 29.28 52.16C29.32 52.19 29.35 52.21 29.39 52.24C29.43 52.26 29.48 52.29 29.52 52.31C29.6 52.35 29.69 52.38 29.78 52.42C29.83 52.43 29.89 52.45 29.95 52.47C30.06 52.49 30.16 52.5 30.26 52.51C30.26 52.51 30.26 52.51 30.27 52.51C30.23 52.51 30.18 52.51 30.14 52.5C30.22 52.5 30.3 52.5 30.38 52.5C30.61 52.48 30.84 52.45 31.08 52.4C31.19 52.37 31.29 52.35 31.39 52.31C31.59 52.24 31.78 52.15 31.98 52.06C32.07 52.01 32.16 51.95 32.25 51.9C32.36 51.82 32.47 51.74 32.57 51.65C32.66 51.57 32.75 51.49 32.83 51.4C32.88 51.34 32.93 51.28 32.98 51.21C33.05 51.11 33.11 51 33.16 50.89C33.21 50.78 33.26 50.68 33.3 50.57C33.33 50.46 33.36 50.36 33.38 50.25C33.4 50.15 33.41 50.06 33.42 49.96C33.42 49.87 33.42 49.78 33.42 49.69C33.42 49.64 33.41 49.59 33.4 49.55C33.38 49.48 33.36 49.41 33.34 49.34C33.32 49.28 33.29 49.23 33.27 49.17C33.24 49.12 33.21 49.06 33.18 49.01C33.16 48.99 33.14 48.97 33.13 48.95C33.1 48.92 33.06 48.89 33.03 48.86C32.96 48.81 32.89 48.75 32.82 48.7C32.63 48.58 32.44 48.46 32.25 48.36C31.76 48.13 31.27 47.88 30.77 47.65C30.44 47.67 30.1 47.6 29.81 47.44C29.8 47.45 29.79 47.46 29.78 47.47Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M15.52 77.71C14.97 77.67 14.47 77.54 13.96 77.33C13.08 76.97 12.3 76.29 11.77 75.51C11.16 74.62 10.81 73.53 10.58 72.48C10.32 71.31 10.26 70.1 10.29 68.91C10.32 67.73 10.52 66.55 10.88 65.42C11.2 64.42 11.7 63.48 12.41 62.71C13.06 61.99 13.88 61.47 14.79 61.14C15.61 60.84 16.53 60.84 17.17 61.5C17.26 61.6 17.35 61.7 17.42 61.82C17.49 61.79 17.55 61.77 17.62 61.75C18.1 61.62 18.55 61.71 18.98 61.93C19.55 62.22 20.1 62.53 20.66 62.83C21.64 63.36 22.46 64.12 23.16 64.99C23.81 65.81 24.26 66.78 24.46 67.81C24.67 68.88 24.59 69.92 24.23 70.95C23.48 73.09 22.05 74.97 20.19 76.27C19.26 76.91 18.26 77.38 17.16 77.61C16.74 77.7 16.31 77.75 15.88 77.75C15.76 77.72 15.64 77.72 15.52 77.71ZM14.65 73.47C14.69 73.53 14.74 73.59 14.78 73.65C14.83 73.7 14.88 73.74 14.92 73.79C14.99 73.85 15.07 73.9 15.14 73.96C15.21 74 15.27 74.04 15.34 74.08C15.39 74.1 15.45 74.12 15.5 74.15C15.54 74.16 15.57 74.17 15.61 74.19C15.69 74.2 15.77 74.21 15.86 74.22H15.87C15.83 74.22 15.8 74.22 15.76 74.21C15.85 74.21 15.94 74.21 16.02 74.21C16.16 74.2 16.31 74.17 16.44 74.15C16.64 74.11 16.83 74.06 17.02 73.99C17.14 73.94 17.26 73.89 17.38 73.84C17.63 73.71 17.86 73.57 18.1 73.42C18.35 73.24 18.58 73.06 18.82 72.87C19.07 72.63 19.32 72.39 19.55 72.12C19.74 71.89 19.92 71.65 20.09 71.41C20.27 71.14 20.43 70.86 20.58 70.57C20.7 70.29 20.82 70.01 20.93 69.72C20.97 69.6 21 69.47 21.03 69.34C21.04 69.27 21.05 69.21 21.06 69.14C21.06 69.08 21.06 69.02 21.06 68.95C21.04 68.79 21.02 68.62 20.99 68.46C20.95 68.32 20.92 68.19 20.87 68.05C20.83 67.96 20.79 67.87 20.75 67.78C20.7 67.68 20.64 67.59 20.58 67.49C20.43 67.27 20.26 67.06 20.1 66.85C20.02 66.76 19.93 66.68 19.85 66.6C19.65 66.44 19.46 66.28 19.25 66.13C18.6 65.71 17.89 65.35 17.2 65.01C16.94 64.88 16.74 64.68 16.59 64.44C16.34 64.55 16.06 64.6 15.78 64.58C15.74 64.6 15.69 64.62 15.66 64.63C15.57 64.68 15.49 64.73 15.41 64.78C15.34 64.83 15.26 64.89 15.19 64.94C15.13 64.99 15.07 65.05 15.02 65.12C14.94 65.21 14.86 65.31 14.79 65.41C14.69 65.56 14.6 65.71 14.51 65.87C14.42 66.07 14.34 66.26 14.27 66.45C14.17 66.76 14.09 67.07 14.02 67.4C13.94 67.84 13.88 68.27 13.84 68.71C13.81 69.29 13.82 69.87 13.86 70.46C13.9 70.87 13.95 71.28 14.02 71.68C14.09 71.98 14.17 72.29 14.27 72.59C14.37 72.86 14.48 73.13 14.6 73.39C14.64 73.45 14.67 73.51 14.7 73.56C14.68 73.53 14.66 73.5 14.64 73.47C14.64 73.45 14.64 73.46 14.65 73.47Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="80" height="75" viewBox="0 0 80 75" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M2.06999 74.16C1.19999 74.16 0.429986 73.49 0.319986 72.63C0.269986 72.22 0.319964 71.81 0.359964 71.4C0.379964 71.19 0.379962 70.97 0.419962 70.76C0.489962 70.35 0.559974 69.95 0.619974 69.55C0.809974 68.25 0.959986 66.94 1.06999 65.62C1.23999 62.96 1.21995 60.29 1.46995 57.63C1.59995 56.25 1.75998 54.89 1.93998 53.52C2.10998 52.16 2.24001 50.8 2.34001 49.43C2.45001 46.57 2.40998 43.72 2.49998 40.86C2.58998 38.08 2.92997 35.32 3.11997 32.54C3.30997 28.7 3.28001 24.87 3.34001 21.03C3.37001 19.12 3.34001 17.21 3.28001 15.3C3.25001 14.39 3.2 13.47 3.21 12.56C3.23 11.52 3.27 10.49 3.33 9.45001C3.4 8.25001 3.53 7.04998 3.65 5.84998C3.77 4.68998 3.85996 3.52999 3.97996 2.37C4.05996 1.5 4.88996 0.840027 5.72996 0.840027C6.68996 0.840027 7.49998 1.63999 7.49998 2.60999C7.49998 2.64999 7.49998 2.67997 7.49998 2.71997C7.49998 2.83997 7.48 2.96002 7.46 3.08002C7.25 5.22002 7.04996 7.38003 6.85996 9.53003C6.80996 10.45 6.76998 11.36 6.74998 12.28C6.73998 13.17 6.76997 14.07 6.79997 14.97C6.86997 16.97 6.88998 18.96 6.87998 20.96C6.85998 22.8 6.80997 24.64 6.79997 26.49C6.78997 28.51 6.75 30.52 6.65 32.54C6.54 34.77 6.29997 36.99 6.11997 39.2C6.02997 40.74 5.98 42.28 5.96 43.83C5.94 45.55 5.93998 47.27 5.87998 48.99C5.81998 50.69 5.63996 52.37 5.41996 54.04C5.20996 55.7 5.01998 57.35 4.87998 59.01C4.72998 61.41 4.75998 63.82 4.55998 66.21C4.50998 66.83 4.43997 67.46 4.36997 68.08C4.62997 67.88 4.89 67.68 5.15 67.47C6.38 66.51 7.64996 65.59 8.85996 64.61C10.14 63.57 11.4 62.5 12.69 61.48C14.07 60.38 15.45 59.28 16.82 58.16C18.32 56.82 19.82 55.46 21.32 54.11C22.81 52.75 24.37 51.46 25.89 50.14C27.47 48.72 29.03 47.28 30.65 45.91C32.31 44.49 33.98 43.08 35.63 41.65C37.06 40.33 38.47 38.99 39.88 37.66C41.28 36.34 42.71 35.05 44.08 33.7C45.45 32.35 46.77 30.95 48.14 29.6C48.77 28.98 49.41 28.38 50.06 27.79C50.77 27.13 51.46 26.46 52.15 25.79C52.83 25.12 53.47 24.41 54.15 23.73C54.79 23.09 55.45 22.45 56.12 21.84C57.52 20.56 58.98 19.33 60.33 18C61.39 16.95 62.39 15.84 63.4 14.73C62.89 14.31 62.37 13.89 61.85 13.48C60.11 12.12 58.2999 10.85 56.4699 9.59998C55.8299 9.19998 55.2 8.80997 54.56 8.40997C54.03 8.08997 53.49 7.75002 53.07 7.27002C52.55 6.68002 52.28 5.84001 52.6 5.07001C52.91 4.34001 53.51 3.86002 54.3 3.71002C54.84 3.61002 55.39 3.57999 55.94 3.54999C56.67 3.50999 57.4 3.48 58.13 3.44C59.75 3.29 61.3599 3.04999 62.9699 2.79999C64.9699 2.48999 66.94 2 68.95 1.81C70.91 1.62 72.95 1.73001 74.87 2.14001C75.27 2.23001 75.68 2.29997 76.08 2.40997C76.7 2.57997 77.39 2.70998 77.87 3.16998C78.59 3.22998 79.2 3.74002 79.44 4.46002C79.73 5.34002 79.46 6.25001 79.39 7.14001C79.28 8.84001 79.2199 10.53 79.2199 12.23C79.2199 14.09 79.21 15.96 79.19 17.83C79.17 19.67 79.1 21.52 78.98 23.36C78.91 24.4 78.84 25.44 78.76 26.48C78.72 27 78.7 27.59 78.4699 28.07C78.2 28.62 77.7899 28.96 77.2199 29.16C76.5999 29.37 75.93 29.16 75.42 28.8C74.92 28.45 74.58 27.82 74.25 27.32C73.59 26.31 72.98 25.27 72.33 24.25C71.81 23.49 71.29 22.73 70.77 21.97C70.23 21.19 69.65 20.45 69.05 19.72C68.74 19.4 68.44 19.06 68.12 18.76C67.74 18.42 67.36 18.08 66.98 17.73C67.03 17.78 67.09 17.83 67.15 17.88C66.81 17.59 66.47 17.3 66.13 17C65.43 17.76 64.74 18.53 64.04 19.29C62.77 20.68 61.33 21.91 59.92 23.17C58.57 24.38 57.2199 25.62 55.9699 26.93C55.2599 27.68 54.55 28.41 53.82 29.13C53.19 29.74 52.53 30.33 51.89 30.93C50.5 32.26 49.13 33.62 47.78 35C46.44 36.38 45.06 37.7 43.65 39C41.8 40.71 39.98 42.46 38.13 44.18C37.23 45.02 36.27 45.8 35.33 46.59C34.38 47.39 33.44 48.19 32.49 49C31.07 50.26 29.67 51.56 28.23 52.8C26.73 54.1 25.23 55.4 23.73 56.7C22.29 58.02 20.84 59.32 19.38 60.62C18.63 61.29 17.82 61.91 17.04 62.54C16.3 63.14 15.55 63.73 14.81 64.32C13.44 65.41 12.13 66.57 10.74 67.64C9.93997 68.26 9.12998 68.89 8.30998 69.51C7.58998 70.06 6.85996 70.6 6.16996 71.18C5.94996 71.36 5.74 71.55 5.52 71.73C5.16 72.06 4.81 72.38 4.46 72.72C4.17 72.99 3.88995 73.27 3.59995 73.54C3.15995 73.95 2.65999 74.15 2.06999 74.16ZM71.92 11.24C71.25 11.94 70.57 12.62 69.87 13.28C69.45 13.67 69.02 14.06 68.6 14.45C68.97 14.77 69.34 15.09 69.7 15.41C70.43 16.07 71.17 16.72 71.8 17.48C72.45 18.25 73.05 19.04 73.63 19.87C74.25 20.77 74.88 21.67 75.4699 22.58C75.6199 19.52 75.67 16.47 75.68 13.4C75.68 11.73 75.67 10.07 75.77 8.40002C75.79 8.09002 75.81 7.77001 75.82 7.45001C74.47 8.67001 73.18 9.93999 71.92 11.24ZM69.67 5.28003C68.26 5.39003 66.89 5.69 65.51 5.94C64.44 6.13 63.37 6.31997 62.29 6.46997C61.2 6.62997 60.1 6.79002 59 6.90002C58.96 6.90002 58.91 6.90997 58.87 6.90997C59.48 7.31997 60.07 7.73997 60.66 8.15997C62.2099 9.26997 63.77 10.38 65.23 11.6C65.45 11.79 65.67 11.97 65.89 12.15C66.65 11.44 67.42 10.75 68.16 10.02C69.46 8.72002 70.71 7.37999 72.05 6.10999C72.31 5.85999 72.58 5.62 72.84 5.38C72.5 5.34 72.17 5.30002 71.83 5.27002C71.49 5.25002 71.15 5.23999 70.81 5.23999C70.43 5.24999 70.05 5.26003 69.67 5.28003Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,13 @@
|
||||
<svg width="81" height="85" viewBox="0 0 81 85" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M2.46002 77.05C1.54002 76.93 0.770009 76 0.950009 75.06C1.04001 74.57 1.24997 74.15 1.59997 73.79C2.35997 73.02 3.24999 72.37 4.11999 71.74C4.90999 71.16 5.7 70.57 6.5 70C8.2 68.79 9.89998 67.6 11.61 66.41C14.56 64.37 17.52 62.34 20.45 60.26C20.26 59.99 20.06 59.72 19.88 59.46C19.43 58.82 18.97 58.17 18.56 57.5C18.09 56.71 17.61 55.93 17.15 55.15C16.82 54.6 16.5 54.04 16.19 53.49C15.98 53.1 15.76 52.72 15.54 52.33C15.35 52 15.19 51.67 15.09 51.33C14.79 50.6 14.96 49.76 15.63 49.24C15.98 48.96 16.42 48.84 16.86 48.88C18.56 48.74 20.25 48.41 21.96 48.33C22.89 48.29 23.8 48.24 24.73 48.25C25.79 48.26 26.85 48.29 27.91 48.34C28.8 48.38 29.69 48.43 30.58 48.48C31.96 48.56 33.39 48.66 34.72 49.05C35.58 49.3 36.32 49.97 36.32 50.92C36.32 51.4 36.14 51.82 35.89 52.21C36.04 52.77 35.99 53.38 35.89 53.94C35.73 54.87 35.37 55.79 35.09 56.69C34.75 57.82 34.48 58.97 34.2 60.12C33.93 61.64 33.65 63.17 33.4 64.69C33.28 65.45 33.14 66.2 33 66.96C32.93 67.29 32.87 67.62 32.8 67.96C32.75 68.19 32.71 68.43 32.67 68.67C32.6 69.14 32.43 69.55 32.13 69.91C31.55 70.62 30.38 70.88 29.65 70.23C29.4 70.02 29.19 69.79 28.97 69.55C28.01 68.5 27 67.51 25.98 66.52C24.83 65.41 23.73 64.25 22.68 63.05C20.05 64.93 17.38 66.76 14.71 68.59C13.23 69.6 11.77 70.62 10.31 71.65C9.56999 72.18 8.82997 72.7 8.09997 73.24C6.84997 74.15 5.57001 75.05 4.39001 76.05C4.44001 76 4.49999 75.95 4.55999 75.9C4.44999 75.99 4.34999 76.09 4.23999 76.19C3.92999 76.73 3.37997 77.09 2.71997 77.09C2.61997 77.07 2.54002 77.06 2.46002 77.05ZM28.96 58.48C27.83 59.32 26.68 60.14 25.54 60.96C25.6 61.03 25.66 61.1 25.73 61.18C26.75 62.32 27.85 63.41 28.95 64.47C29.2 64.71 29.45 64.96 29.7 65.2C29.72 65.1 29.73 65 29.75 64.9C29.96 63.63 30.17 62.37 30.4 61.11C30.51 60.49 30.59 59.85 30.74 59.23C30.91 58.56 31.08 57.89 31.24 57.22C31.29 57.02 31.34 56.82 31.39 56.62C30.6 57.27 29.78 57.87 28.96 58.48ZM23.34 58.19C24.08 57.65 24.81 57.12 25.55 56.58C27.03 55.51 28.5 54.42 29.93 53.28C30.38 52.88 30.82 52.48 31.26 52.07C31.03 52.05 30.79 52.03 30.56 52.02C29.08 51.93 27.61 51.86 26.13 51.81C24.78 51.76 23.43 51.81 22.09 51.86C21.22 51.95 20.35 52.04 19.48 52.14C20.35 53.68 21.25 55.19 22.23 56.65C22.19 56.59 22.14 56.53 22.1 56.46C22.5 57.04 22.91 57.62 23.34 58.19Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M45.06 36.49C45.04 36.49 45.02 36.48 45 36.47C44.41 36.33 43.92 35.81 43.77 35.24C43.66 34.83 43.7 34.4 43.87 34.03C43.69 33.76 43.52 33.5 43.35 33.24C42.38 31.81 41.43 30.36 40.3 29.05C39.92 28.63 39.53 28.23 39.12 27.85C38.23 27.1 37.25 26.5 36.32 25.81C35.68 25.33 34.98 24.86 34.41 24.3C33.8 23.71 33.69 22.62 34.26 21.97C34.48 21.72 34.7 21.51 35.01 21.37C35.33 21.24 35.66 21.21 36 21.19C35.92 21.19 35.84 21.2 35.76 21.21C36.94 21.09 38.13 21.08 39.31 21.09C40.43 21.1 41.53 21.21 42.65 21.3C43.66 21.39 44.67 21.51 45.68 21.63C45.82 21.65 45.96 21.66 46.09 21.68C46.64 18.2 47.16 14.73 47.56 11.23C47.72 9.78999 47.85 8.35003 47.98 6.90003C48.07 5.51003 48.2 4.11999 48.14 2.72999C48.14 2.70999 48.13 2.7 48.13 2.68C48.04 2.31 48.06 1.91002 48.21 1.57002C48.6 0.640016 49.62 0.300003 50.53 0.620003C51.24 0.880003 51.55 1.59004 51.65 2.28004C51.74 2.85004 51.7 3.47 51.69 4.05C51.69 4.3 51.67 4.55 51.65 4.8C51.59 5.78 51.54 6.77001 51.45 7.75001C51.26 9.82001 51.05 11.88 50.81 13.95C50.5 16.61 50.07 19.26 49.65 21.91C50.04 21.92 50.42 21.92 50.81 21.91C51.89 21.87 52.98 21.81 54.06 21.82C55.06 21.83 56.27 21.93 57.02 22.68C57.69 23.34 57.91 24.33 57.57 25.22C57.19 26.2 56.4 26.84 55.61 27.49C55.23 27.79 54.86 28.09 54.49 28.39C53.85 28.96 53.22 29.53 52.62 30.15C51.92 30.87 51.23 31.6 50.55 32.33C49.97 32.96 49.36 33.57 48.73 34.15C48.71 34.61 48.61 35.06 48.33 35.43C47.95 35.92 47.42 36.11 46.83 36.14C46.91 36.14 46.99 36.13 47.07 36.12C46.93 36.14 46.78 36.15 46.65 36.15C46.33 36.4 45.93 36.54 45.52 36.54C45.36 36.54 45.21 36.52 45.06 36.49ZM42.41 26.11C43.49 27.22 44.38 28.49 45.25 29.76C45.26 29.49 45.27 29.23 45.28 28.96C45.34 27.84 45.41 26.74 45.52 25.63C45.54 25.48 45.55 25.33 45.57 25.17C44.78 25.09 43.98 25 43.19 24.91C42.41 24.82 41.63 24.76 40.85 24.7C41.39 25.13 41.91 25.6 42.41 26.11ZM49.1 25.53C49.01 26.17 48.96 26.81 48.9 27.45C48.87 27.96 48.85 28.47 48.83 28.97C49.51 28.24 50.18 27.49 50.92 26.83C51.38 26.41 51.83 25.97 52.32 25.58C52.41 25.51 52.49 25.44 52.58 25.37C51.89 25.39 51.2 25.43 50.52 25.45C50.05 25.47 49.58 25.45 49.11 25.43C49.11 25.46 49.1 25.5 49.1 25.53Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M76.19 81.46C75.8 80.62 75.44 79.76 75.06 78.91C74.72 78.26 74.41 77.59 74.02 76.97C73.56 76.22 73.09 75.47 72.63 74.73C71.08 72.48 69.56 70.22 68.02 67.96C67.69 67.48 67.38 66.97 67.03 66.5C66.5 65.81 65.98 65.12 65.45 64.44C64.73 63.5 63.95 62.62 63.18 61.72C62.75 62.11 62.32 62.51 61.89 62.89C60.44 64.15 59.01 65.43 57.45 66.54C56.97 66.88 56.49 67.23 55.99 67.56C55.17 68.1 54.01 68.74 53.05 68.13C52.67 67.89 52.36 67.63 52.18 67.21C52.02 66.83 51.95 66.43 51.91 66.02C51.86 65.45 51.82 64.88 51.79 64.31C51.66 62.35 51.65 60.38 51.59 58.42C51.55 57.06 51.5 55.69 51.48 54.33C51.46 53.21 51.43 52.09 51.48 50.97C51.51 50.3 51.54 49.59 51.74 48.93C51.31 48.7 50.92 48.39 50.56 48.08C49.83 47.45 49.62 46.39 50.24 45.6C50.8 44.87 51.99 44.65 52.72 45.28C52.9 45.44 53.08 45.58 53.27 45.73C53.32 45.77 53.38 45.8 53.44 45.83C53.47 45.84 53.5 45.85 53.53 45.87C53.58 45.89 53.64 45.9 53.69 45.92C54.06 45.98 54.42 46.03 54.79 46.06C54.71 46.05 54.63 46.05 54.55 46.04C56.78 46.18 59.03 46.46 61.2 47.06C62.27 47.36 63.34 47.65 64.41 47.94C65.37 48.21 66.33 48.46 67.29 48.72C68.04 48.92 68.81 49.08 69.58 49.24C69.94 49.3 70.29 49.36 70.66 49.41C71.14 49.48 71.55 49.55 71.95 49.84C72.66 50.36 72.8 51.32 72.43 52.07C72.21 52.55 71.98 52.99 71.67 53.42C71.18 54.11 70.61 54.74 70.06 55.37C69.45 56.07 68.81 56.73 68.12 57.35C67.42 57.99 66.71 58.59 65.99 59.2C65.92 59.25 65.86 59.31 65.79 59.37C66.42 60.09 67.03 60.83 67.66 61.57C68.28 62.3 68.83 63.09 69.41 63.85C69.93 64.53 70.41 65.25 70.89 65.96C71.92 67.48 72.94 69 73.98 70.51C74.55 71.35 75.16 72.17 75.7 73.03C76.21 73.86 76.75 74.67 77.22 75.53C77.57 76.19 77.97 76.84 78.27 77.53C78.68 78.45 79.08 79.39 79.5 80.31C79.57 80.43 79.63 80.56 79.7 80.69C80.28 80.98 80.68 81.58 80.68 82.26C80.68 83.22 79.87 84.03 78.91 84.03C77.49 84.01 76.73 82.63 76.19 81.46ZM55.06 54.83C55.09 55.92 55.12 57.02 55.15 58.11C55.2 59.98 55.24 61.84 55.33 63.71C55.44 63.63 55.55 63.55 55.66 63.48C56.18 63.11 56.68 62.68 57.18 62.28C58.03 61.61 58.83 60.87 59.65 60.16C60.05 59.79 60.45 59.43 60.86 59.07C60.7 58.91 60.56 58.73 60.41 58.55C60.14 58.25 59.87 57.94 59.6 57.64C59.52 57.55 59.44 57.46 59.36 57.37C59.36 57.37 59.37 57.38 59.38 57.38C57.99 55.78 56.93 53.92 55.54 52.31C55.38 52.14 55.21 51.97 55.04 51.81C55 52.82 55.03 53.83 55.06 54.83ZM62.28 55.36C62.46 55.54 62.62 55.74 62.78 55.93C63.01 56.2 63.25 56.46 63.48 56.72C64.07 56.2 64.66 55.69 65.26 55.18C65.6 54.87 65.94 54.56 66.27 54.25C66.57 53.97 66.85 53.65 67.14 53.34C67.12 53.36 67.1 53.39 67.08 53.41C67.36 53.09 67.64 52.78 67.91 52.46C67.86 52.45 67.82 52.44 67.77 52.43C66.87 52.23 65.99 52 65.1 51.76C62.98 51.18 60.87 50.54 58.72 50.09C58.54 50.05 58.37 50.02 58.19 49.99C58.53 50.37 58.85 50.77 59.15 51.18C59.65 51.86 60.11 52.59 60.63 53.26C61.12 53.89 61.61 54.52 62.11 55.15C62.11 55.15 62.1 55.14 62.09 55.13C62.1 55.14 62.11 55.16 62.12 55.17C62.13 55.18 62.14 55.19 62.14 55.19C62.15 55.21 62.17 55.22 62.18 55.23C62.17 55.22 62.16 55.21 62.15 55.2C62.2 55.27 62.24 55.31 62.28 55.36Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path d="M62.12 55.19L62.13 55.2C62.13 55.19 62.13 55.19 62.12 55.19Z" fill="rgba(191, 192, 191, 1)" />
|
||||
<path d="M62.11 55.17L62.12 55.18C62.12 55.17 62.12 55.17 62.11 55.17Z" fill="rgba(191, 192, 191, 1)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,8 @@
|
||||
<svg width="66" height="77" viewBox="0 0 66 77" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M54.45 76.22C53.56 75.7 52.91 74.81 52.33 73.99C51.55 72.91 50.8801 71.74 50.2901 70.55C49.2001 68.35 48.3701 66.03 47.5401 63.72C46.2501 60.18 44.9701 56.64 43.9301 53.01C43.5301 51.62 43.13 50.22 42.72 48.83C42.46 48.08 42.2 47.33 41.95 46.58C41.73 45.98 41.45 45.4 41.21 44.8C40.98 44.25 40.7001 43.71 40.4301 43.17C40.0501 42.48 39.67 41.79 39.25 41.13C39 40.76 38.7201 40.4 38.4301 40.06C38.2301 39.85 38.04 39.65 37.83 39.46C37.73 39.38 37.62 39.3 37.52 39.22C37.41 39.15 37.31 39.09 37.2 39.02C37.1 38.97 36.99 38.93 36.89 38.89C36.8 38.86 36.7 38.83 36.6 38.81C36.51 38.79 36.42 38.78 36.33 38.77C36.22 38.77 36.11 38.77 36.01 38.77C35.89 38.78 35.76 38.8 35.64 38.82C35.21 38.92 34.79 39.03 34.37 39.17C33.58 39.45 32.79 39.76 32 40.05C31.23 40.34 30.44 40.59 29.66 40.84C28.93 41.07 28.16 41.23 27.41 41.38C26.52 41.55 25.63 41.7 24.73 41.82C21.54 42.26 18.32 42.17 15.12 42.31C13.74 42.42 12.37 42.56 10.98 42.66C9.63999 42.76 8.29997 42.8 6.95997 42.88C6.54997 42.92 6.15 42.98 5.74 43.05C4.85 43.25 3.96997 43.47 3.07997 43.64C2.71997 43.71 2.32998 43.75 1.96998 43.7C1.59998 43.65 1.23996 43.52 0.949965 43.29C0.689965 43.09 0.499989 42.83 0.349989 42.54C0.0699893 41.98 -0.10002 41.33 0.0899796 40.7C0.22998 40.25 0.400067 39.84 0.680067 39.47C0.820067 39.29 0.970019 39.11 1.13002 38.95C1.14002 38.45 1.36006 37.96 1.80006 37.59C2.37006 37.11 3.02003 36.76 3.64003 36.38C4.19003 36.04 4.75006 35.7 5.30006 35.35C6.08006 34.87 6.83999 34.38 7.59999 33.89C9.32999 32.79 11.05 31.68 12.77 30.57C14.34 29.56 15.93 28.57 17.51 27.57C19.12 26.55 20.7101 25.5 22.3101 24.48C25.5401 22.43 28.69 20.26 31.89 18.16C31.83 18.2 31.77 18.25 31.7 18.29C34.79 16.19 37.86 14.07 40.95 11.96C42.7 10.76 44.46 9.55999 46.22 8.35999C47.77 7.30999 49.3 6.22003 50.88 5.21003C52.81 3.99003 54.73 2.73002 56.77 1.70002C57.77 1.20002 58.8101 0.769992 59.9201 0.609992C61.0601 0.439992 62.1301 0.75999 63.0601 1.41999C63.4501 1.69999 63.7901 2.12998 64.0401 2.53998C64.3101 2.98998 64.54 3.45998 64.7 3.96998C65.07 5.17998 65.2 6.43002 65.24 7.70002C65.33 10.64 64.79 13.58 64.4 16.48C64.16 18.25 63.87 20 63.63 21.77C63.07 25.95 62.55 30.13 62.03 34.31C61.58 37.95 61.15 41.6 60.86 45.26C60.79 46.18 60.71 47.1 60.64 48.01C60.64 48 60.64 47.98 60.64 47.97C60.61 48.46 60.5701 48.95 60.5401 49.43V49.42C60.5401 49.45 60.5401 49.48 60.5401 49.51C60.5401 49.54 60.54 49.58 60.53 49.61C60.52 49.75 60.51 49.89 60.5 50.02C60.5 50 60.5 50 60.5 49.98C60.46 50.62 60.41 51.25 60.37 51.89C60.37 51.88 60.37 51.87 60.37 51.87C60.13 55.53 59.87 59.19 59.49 62.84C59.29 64.79 59.07 66.74 58.84 68.69C58.62 70.55 58.3201 72.39 57.9301 74.22C57.7801 74.94 57.5001 75.59 56.9301 76.06C56.5501 76.38 56.1 76.53 55.64 76.53C55.22 76.55 54.82 76.44 54.45 76.22ZM51.19 63.43C51.89 65.36 52.62 67.28 53.53 69.13C53.94 69.92 54.38 70.68 54.85 71.42C55.35 68.41 55.65 65.37 55.97 62.33C56.35 58.74 56.58 55.13 56.84 51.52C56.83 51.6 56.83 51.68 56.82 51.76C56.86 51.16 56.9 50.55 56.94 49.95C56.95 49.83 56.96 49.71 56.96 49.59C56.96 49.59 56.96 49.6 56.96 49.61C57.01 48.93 57.05 48.26 57.1 47.59C57.1 47.67 57.09 47.75 57.08 47.83C57.34 43.93 57.75 40.03 58.21 36.15C58.65 32.4 59.09 28.66 59.6 24.92C59.93 22.52 60.25 20.12 60.6 17.72C60.99 15.08 61.41 12.43 61.61 9.77003C61.66 8.86003 61.67 7.94003 61.62 7.02003C61.58 6.56003 61.5101 6.11999 61.4301 5.66999C61.3801 5.42999 61.31 5.19002 61.24 4.95002C61.2 4.86002 61.17 4.77 61.13 4.68C61.08 4.59 61.03 4.49998 60.98 4.40998C60.94 4.35998 60.91 4.31003 60.86 4.27003C60.84 4.25003 60.8301 4.23998 60.8101 4.21998C60.7901 4.20998 60.77 4.20001 60.76 4.19001C60.74 4.18001 60.72 4.16998 60.69 4.15998C60.68 4.15998 60.67 4.15003 60.66 4.15003C60.64 4.15003 60.62 4.14002 60.59 4.14002C60.54 4.14002 60.4801 4.14001 60.4301 4.13001C60.3501 4.14001 60.27 4.14998 60.19 4.15998C59.98 4.20998 59.78 4.27002 59.58 4.33002C59.18 4.48002 58.7901 4.65002 58.41 4.83002C55.32 6.40002 52.46 8.41001 49.58 10.32C49.65 10.28 49.71 10.24 49.77 10.2C43.23 14.69 36.7 19.2 30.09 23.59C23.69 27.84 17.18 31.92 10.72 36.08C9.67998 36.75 8.63999 37.41 7.59999 38.07C7.10999 38.39 6.62001 38.69 6.12001 38.99C6.10001 39.14 6.06001 39.29 6.00001 39.44C6.04001 39.43 6.07 39.43 6.11 39.42C7.39 39.28 8.67997 39.27 9.95997 39.21C12.09 39.05 14.21 38.83 16.35 38.73C17.34 38.69 18.34 38.69 19.33 38.68C20.26 38.66 21.19 38.61 22.13 38.55C22.97 38.47 23.82 38.39 24.66 38.26C25.48 38.15 26.28 37.99 27.1 37.84C27.62 37.71 28.13 37.57 28.65 37.45C29.13 37.33 29.6001 37.15 30.0601 36.99C31.7801 36.35 33.52 35.57 35.34 35.29C38.61 34.78 41.23 37.4 42.7 40.03C43.34 41.19 44 42.36 44.5 43.59C44.78 44.26 45.08 44.93 45.32 45.62C45.57 46.36 45.83 47.1 46.09 47.84C46.06 47.77 46.04 47.69 46.01 47.62C46.33 48.54 46.57 49.49 46.84 50.42C47.11 51.35 47.34 52.29 47.64 53.21C48.25 55.12 48.87 57.01 49.53 58.9C49.51 58.83 49.48 58.76 49.46 58.68C50.06 60.27 50.61 61.85 51.19 63.43Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M50.8299 45.38C50.5499 44.97 50.3799 44.5 50.1899 44.06C50.0799 43.9 50 43.72 49.92 43.53C49.68 43.08 49.43 42.62 49.22 42.15C48.74 41.08 48.34 39.99 47.8299 38.94C47.4599 38.25 47.08 37.57 46.74 36.87C46.38 36.13 46.0499 35.39 45.6899 34.65C45.7299 34.72 45.76 34.78 45.8 34.85C45.44 34.14 45.1 33.44 44.84 32.71C44.67 32.46 44.5 32.21 44.34 31.96C44.25 31.82 44.15 31.69 44.05 31.55C43.94 31.51 43.83 31.48 43.72 31.45C43.68 31.45 43.63 31.44 43.59 31.43C42.8 31.39 42.02 31.39 41.23 31.31C41.17 31.3 41.11 31.29 41.04 31.29C39.28 31.23 37.52 31.29 35.76 31.35C35.43 31.36 35.13 31.27 34.87 31.12C34.85 31.12 34.82 31.12 34.8 31.13C34.48 31.15 34.16 31.17 33.84 31.18C33.75 31.19 33.66 31.2 33.5799 31.21C33.5399 31.22 33.51 31.23 33.47 31.24C33.32 31.29 33.17 31.36 33.02 31.43C32.47 31.66 31.84 31.58 31.36 31.27C30.62 31.14 30.02 30.54 29.9 29.77C29.75 28.81 30.43 28.12 31.11 27.57C31.22 27.47 31.3299 27.39 31.4499 27.31C31.4599 27.3 31.47 27.3 31.47 27.29C31.58 27.22 31.68 27.15 31.8 27.09C31.93 27.01 32.0699 26.94 32.1999 26.86C32.3199 26.8 32.43 26.75 32.55 26.7C32.64 26.58 32.73 26.47 32.84 26.36C33.08 26.12 33.35 25.91 33.61 25.7C34.27 25.18 34.9699 24.72 35.6999 24.3C36.7299 23.71 37.79 23.19 38.86 22.68C39.95 22.16 41.06 21.72 42.16 21.22C42.98 20.79 43.76 20.31 44.55 19.85C45.4 19.35 46.26 18.88 47.12 18.4C48.05 17.88 48.96 17.35 49.88 16.82C50.33 16.57 50.78 16.32 51.23 16.08C51.71 15.83 52.2699 15.5 52.8199 15.44C53.5599 15.36 54.27 15.73 54.61 16.35C54.77 16.51 54.91 16.7 54.99 16.93C55.08 17.18 55.19 17.45 55.17 17.72C55.16 17.95 55.14 18.18 55.13 18.41V18.4C55.07 19.37 55.0299 20.34 55.0799 21.31C55.1499 22.11 55.28 22.91 55.26 23.72C55.24 24.6 55.2199 25.47 55.1899 26.35C55.1699 27.29 55.16 28.23 55.13 29.17C55.1 30.07 55.04 30.97 55.03 31.88C55.02 32.83 55.03 33.79 55.04 34.74C55.05 35.72 54.97 36.7 54.91 37.68C54.79 39.67 54.69 41.7 54.3 43.66C54.09 44.68 53.68 45.91 52.46 46.03C52.4 46.03 52.33 46.04 52.26 46.04C51.73 46.06 51.1499 45.85 50.8299 45.38Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg width="82" height="78" viewBox="0 0 82 78" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M23.21 77.03C22.64 76.68 22.15 76.23 21.65 75.8C21.18 75.39 20.72 74.97 20.25 74.55C19.69 74.07 19.1301 73.6 18.5601 73.14C17.4201 72.21 16.42 71.16 15.49 70.02C14.96 69.38 14.4501 68.71 13.9201 68.07C13.3801 67.44 12.8401 66.81 12.3001 66.19C10.9401 64.68 9.60005 63.15 8.28005 61.6C7.58005 60.8 6.87007 60 6.18007 59.2C6.16007 59.17 6.12999 59.14 6.09999 59.11C6.09999 59.1 6.08997 59.1 6.07997 59.09C5.25997 58.17 4.39008 57.28 3.56008 56.36C2.93008 55.66 2.28996 54.97 1.68996 54.25C0.91996 53.32 -0.120026 51.97 0.829974 50.8C1.06997 50.5 1.38 50.29 1.73 50.18C1.52 49.75 1.43007 49.3 1.55007 48.82C1.67007 48.38 1.97001 48 2.37001 47.76C2.88001 47.46 3.54998 47.46 4.08998 47.72C4.42998 47.61 4.75999 47.49 5.09999 47.38C5.93999 47.08 6.77996 46.75 7.68996 46.81C8.13996 46.84 8.58004 46.92 9.02004 46.97C9.03004 46.97 9.04007 46.97 9.05007 46.97C9.81007 46.8 10.56 46.57 11.32 46.4C12.18 46.21 13.02 46.07 13.89 46.06C14.32 46.06 14.7501 46.05 15.1801 46.04C15.4801 46.01 15.78 45.97 16.07 45.92C17.17 45.67 18.27 45.44 19.39 45.23C19.78 45.13 20.1601 45.03 20.5401 44.91C21.1901 44.67 21.84 44.42 22.52 44.25C23.4 44.03 24.32 44.03 25.23 44.05C26.22 44.07 27.2001 44.13 28.1801 44.23C29.0701 44.32 29.95 44.5 30.82 44.68C31.47 44.82 32.1 44.97 32.6 45.45C33 45.83 33.1501 46.38 33.1701 46.91C33.1801 47.2 33.1201 47.47 33.0601 47.75C32.9801 48.12 32.8901 48.48 32.8101 48.85C32.6001 49.74 32.38 50.62 32.15 51.51C31.92 52.36 31.66 53.19 31.45 54.05C31.23 54.94 31.0301 55.84 30.8101 56.73C30.4001 58.45 29.93 60.16 29.45 61.86C29.2 62.78 28.95 63.7 28.71 64.61C28.51 65.4 28.3501 66.2 28.1701 67C27.7101 69.59 27.28 72.18 26.71 74.75C26.54 75.51 26.25 76.23 25.69 76.77C25.3 77.15 24.79 77.34 24.27 77.34C23.9 77.33 23.54 77.23 23.21 77.03ZM10.94 59.28L10.95 59.29V59.3C11.66 60.11 12.3601 60.93 13.0601 61.74C13.9701 62.75 14.88 63.77 15.76 64.8C16.83 66.04 17.83 67.34 18.89 68.58C19.23 68.96 19.59 69.33 19.96 69.68C20.57 70.2 21.1901 70.7 21.8001 71.22C22.3801 71.72 22.96 72.23 23.53 72.74C23.55 72.65 23.57 72.55 23.59 72.46C23.97 70.53 24.29 68.59 24.64 66.66C24.97 64.83 25.46 63.02 25.95 61.23C26.47 59.37 26.9801 57.51 27.4301 55.64C27.6401 54.77 27.8401 53.89 28.0501 53.02C28.2601 52.16 28.53 51.31 28.76 50.45C28.98 49.64 29.19 48.83 29.38 48.01C28.39 47.84 27.4101 47.71 26.4101 47.63C25.6201 47.6 24.82 47.56 24.03 47.59C23.87 47.61 23.7101 47.63 23.5401 47.65C23.2901 47.7 23.06 47.77 22.82 47.85C22.11 48.1 21.42 48.39 20.69 48.56C20.03 48.72 19.3501 48.84 18.6701 48.96C17.8801 49.13 17.1001 49.33 16.3001 49.48C15.3701 49.65 14.42 49.59 13.49 49.62C13.23 49.64 12.97 49.68 12.71 49.72C11.66 49.96 10.62 50.27 9.56996 50.47C8.89996 50.59 8.24997 50.41 7.57997 50.35C7.52997 50.35 7.48007 50.35 7.43007 50.35C7.39007 50.36 7.35008 50.36 7.31008 50.37C7.22008 50.4 7.12005 50.42 7.03005 50.46C7.10005 50.43 7.17 50.41 7.23 50.39C6.33 50.71 5.43004 51 4.52004 51.29C4.34004 51.34 4.15999 51.4 3.96999 51.43C4.27999 51.86 4.61999 52.28 4.96999 52.68C5.55999 53.32 6.12999 53.97 6.71999 54.61C7.38999 55.33 8.07999 56.04 8.71999 56.77C8.70999 56.76 8.69996 56.75 8.68996 56.74C9.43996 57.57 10.19 58.42 10.94 59.28Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path d="M6.16003 59.18C6.16003 59.19 6.16003 59.19 6.16003 59.18V59.18Z" fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M10.98 59.32C10.99 59.32 10.99 59.33 11 59.34C11.01 59.35 11.01 59.36 11.02 59.36C11 59.35 10.99 59.33 10.98 59.32Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path d="M10.96 59.3C10.96 59.3 10.97 59.31 10.98 59.32C10.98 59.32 10.97 59.31 10.96 59.3Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path d="M10.9399 59.27C10.9499 59.28 10.95 59.28 10.95 59.28C10.94 59.28 10.9399 59.27 10.9399 59.27Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M51.28 54.79C51.21 54.74 51.1399 54.7 51.0699 54.65C50.6899 54.5 50.3499 54.24 50.0799 53.89C49.6999 53.4 49.36 52.88 49.02 52.36C48.37 51.38 47.79 50.36 47.16 49.36C47.07 49.24 46.97 49.11 46.87 48.98C46.18 48.25 45.43 47.58 44.73 46.86C43.94 46.04 43.21 45.16 42.48 44.28C41.12 42.64 39.81 40.96 38.43 39.33C38.01 38.9 37.59 38.47 37.18 38.04C36.73 37.58 36.2 37.17 35.72 36.74C35.77 36.79 35.83 36.84 35.89 36.89C34.95 36.12 34.0099 35.34 33.0699 34.56C31.9499 33.63 30.8899 32.6 29.7099 31.76C29.6499 31.72 29.58 31.68 29.51 31.64C28.84 31.52 28.2499 31.08 28.0799 30.37C27.9599 29.85 28.0599 29.33 28.3299 28.92C28.5199 28 29.38 27.44 30.31 27.52C30.36 27.52 30.3999 27.53 30.4499 27.53C31.4799 27.58 32.5 27.62 33.53 27.61C34.73 27.5 35.92 27.31 37.13 27.19C37.69 27.14 38.25 27.05 38.8 26.97C39.45 26.88 40.1 26.82 40.76 26.78C41.23 26.74 41.69 26.7 42.16 26.62C42.57 26.53 42.96 26.4 43.36 26.28C43.29 26.31 43.22 26.33 43.14 26.36C44.04 26.04 44.9299 25.72 45.8299 25.41C45.9499 25.37 46.0699 25.33 46.1999 25.29C46.1799 25.29 46.16 25.3 46.15 25.31C46.37 25.24 46.59 25.16 46.81 25.08C46.74 25.11 46.67 25.13 46.59 25.16C46.96 25.03 47.3299 24.9 47.6999 24.77C47.6299 24.8 47.56 24.82 47.48 24.85C48.39 24.53 49.31 24.29 50.27 24.17C51.1 24.06 51.93 24.09 52.77 24.13C53.48 24.17 54.19 24.22 54.89 24.27C55.12 24.28 55.3499 24.28 55.5799 24.27C56.0899 24.25 56.5899 24.44 56.9599 24.8C57.4299 25.27 57.56 25.93 57.42 26.56C57.4 26.64 57.38 26.73 57.36 26.81C57.32 27.19 57.22 27.58 57.15 27.95C56.93 29.2 56.73 30.45 56.48 31.7C56.5 31.62 56.51 31.55 56.53 31.47C56.27 32.9 56.17 34.33 56.01 35.76C55.83 37.33 55.5199 38.88 55.1999 40.43C54.9899 41.59 54.82 42.76 54.74 43.94C54.74 43.91 54.74 43.88 54.74 43.85C54.74 43.89 54.74 43.93 54.73 43.96C54.73 44 54.73 44.05 54.72 44.08C54.72 44.06 54.72 44.03 54.73 44.01C54.66 45.25 54.65 46.49 54.66 47.74C54.66 48.35 54.67 48.97 54.68 49.58C54.68 49.97 54.6799 50.35 54.6899 50.74C54.6999 51.19 54.71 51.63 54.6 52.06C54.55 52.27 54.4499 52.47 54.3199 52.63C54.1399 53.47 53.89 54.34 53.1 54.79C52.83 54.95 52.5 55.04 52.17 55.04C51.83 55.04 51.53 54.96 51.28 54.79ZM46.1999 29.02C45.3599 29.32 44.51 29.63 43.66 29.89C42.63 30.21 41.56 30.28 40.49 30.34C39.62 30.43 38.76 30.57 37.9 30.67C37.06 30.77 36.21 30.85 35.37 30.96C35.05 31 34.73 31.05 34.42 31.08C34.82 31.42 35.22 31.76 35.62 32.1C36.33 32.69 37.04 33.28 37.75 33.86C38.41 34.4 39.04 34.98 39.67 35.54C40.02 35.85 40.34 36.23 40.67 36.57C40.96 36.87 41.24 37.18 41.51 37.5C42.08 38.17 42.6399 38.85 43.1999 39.54C44.2499 40.85 45.31 42.16 46.41 43.44C46.95 44.04 47.4999 44.63 48.0799 45.2C48.6499 45.76 49.23 46.29 49.74 46.9C50.28 47.55 50.68 48.31 51.1 49.03C51.1 48.93 51.1 48.83 51.1 48.73C51.1 47.87 51.09 47 51.11 46.14C51.14 44.6 51.19 43.08 51.4 41.55C51.55 40.39 51.81 39.24 52.05 38.1C52.16 37.47 52.3 36.84 52.37 36.21C52.46 35.48 52.54 34.74 52.6 34C52.71 32.77 52.89 31.56 53.13 30.34C53.13 30.36 53.12 30.38 53.12 30.39C53.29 29.5 53.4199 28.61 53.5799 27.71C53.5599 27.71 53.55 27.71 53.53 27.71C53.51 27.71 53.4799 27.71 53.4599 27.71C53.4699 27.71 53.48 27.71 53.5 27.71C52.67 27.66 51.84 27.61 51.02 27.64C50.73 27.67 50.44 27.71 50.15 27.76C49.67 27.87 49.2 28 48.72 28.15C48.47 28.24 48.22 28.32 47.98 28.4C47.98 28.4 47.99 28.4 48 28.4C47.97 28.41 47.93 28.42 47.9 28.44C47.89 28.44 47.88 28.45 47.86 28.45C47.84 28.46 47.81 28.47 47.78 28.48C47.79 28.48 47.8 28.47 47.81 28.47C47.77 28.49 47.7299 28.5 47.6899 28.52C47.4399 28.61 47.17 28.7 46.92 28.79C46.99 28.77 47.06 28.74 47.14 28.72C46.81 28.82 46.5099 28.92 46.1999 29.02Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path d="M47.67 28.52C47.65 28.53 47.63 28.54 47.61 28.54C47.63 28.53 47.65 28.53 47.67 28.52Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M75.14 32.15C74.55 32.13 74.02 31.79 73.57 31.42C72.5 30.55 71.5 29.61 70.47 28.7C69.43 27.79 68.47 26.81 67.48 25.85C66.47 24.87 65.43 23.92 64.39 22.97C64.45 23.02 64.5001 23.07 64.5601 23.12C62.8801 21.66 61.16 20.26 59.39 18.92C58.38 18.15 57.36 17.4 56.34 16.64C55.39 15.93 54.48 15.18 53.61 14.37C53.07 13.87 52.58 13.31 52.07 12.78C51.94 12.71 51.81 12.62 51.69 12.51C51.37 12.21 51.14 11.87 51 11.45C50.77 10.78 51.09 9.99001 51.62 9.58001C51.81 9.43001 52.02 9.33002 52.23 9.28002C52.11 9.00002 52.05 8.68002 52.1 8.34002C52.22 7.46002 53.08 6.69998 53.99 6.79998C54.37 6.74998 54.74 6.68 55.11 6.63C55.74 6.54 56.37 6.50999 57 6.43999C57.58 6.37999 58.16 6.27997 58.73 6.16997C59.31 6.05997 59.89 5.99002 60.48 5.90001C61.64 5.63001 62.75 5.22 63.89 4.88C65.18 4.5 66.48 4.15997 67.7701 3.78997C69.05 3.41997 70.33 3.04001 71.6 2.64001C72.58 2.33001 73.5601 2.04997 74.5601 1.84997C75.7101 1.61997 76.9001 1.59996 78.0601 1.40996C78.1401 1.38996 78.2201 1.37002 78.3001 1.34002C78.3101 1.33002 78.32 1.33 78.32 1.32C78.9 0.939998 79.56 0.769988 80.24 1.05999C80.91 1.33999 81.28 1.97002 81.44 2.65001C81.65 3.58001 81.5001 4.50999 81.4001 5.43999C81.2601 6.74999 80.94 8.01998 80.59 9.29998C80.25 10.57 79.9301 11.85 79.6601 13.14C79.5901 13.57 79.54 14 79.5 14.43C79.43 15.57 79.3901 16.72 79.2701 17.85C79.1401 19 78.94 20.14 78.74 21.28C78.53 22.5 78.3 23.71 78.09 24.93C77.9 25.98 77.7901 27.04 77.6701 28.1C77.6501 28.48 77.63 28.85 77.63 29.22C77.62 29.87 77.6701 30.57 77.4001 31.17C77.1001 31.84 76.44 32.24 75.75 32.24C75.55 32.27 75.34 32.23 75.14 32.15ZM77.6 5.04998C76.7 5.13998 75.8101 5.23001 74.9201 5.39001C73.8001 5.65001 72.71 6.01999 71.61 6.36999C70.82 6.61999 70.02 6.85001 69.22 7.08001C67.43 7.59001 65.62 8.03999 63.85 8.61999C63.05 8.87999 62.2601 9.16001 61.4301 9.33001C60.5701 9.52001 59.7 9.6 58.83 9.76C57.93 9.92 57.03 9.99001 56.12 10.08C55.73 10.12 55.34 10.18 54.96 10.23C54.83 10.25 54.6901 10.27 54.5601 10.3C54.6401 10.39 54.7201 10.48 54.8001 10.56C55.3401 11.14 55.91 11.7 56.51 12.24C58.35 13.83 60.3501 15.22 62.2801 16.68C63.7801 17.82 65.2301 19.04 66.6501 20.27C68.0401 21.47 69.3701 22.75 70.6701 24.04C71.8101 25.17 73 26.24 74.19 27.31C74.22 26.99 74.2601 26.67 74.2901 26.35C74.4101 25.18 74.65 24.01 74.86 22.85C75.06 21.7 75.27 20.56 75.47 19.41C75.66 18.32 75.78 17.23 75.86 16.14C75.9 15.3 75.94 14.45 76.0201 13.61C76.11 12.78 76.29 11.96 76.48 11.15C76.66 10.38 76.8401 9.60002 77.0501 8.84002C77.2601 8.07002 77.4801 7.30997 77.6501 6.53997C77.7401 6.03997 77.82 5.54002 77.89 5.03002C77.81 5.03002 77.7 5.03998 77.6 5.04998Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M13.1 58.84C12.12 58.7 11.49 57.8 11.59 56.84C11.66 56.11 11.7201 55.39 11.7801 54.66C11.7801 54.55 11.7901 54.43 11.8001 54.32C11.7301 54.13 11.69 53.92 11.69 53.7C11.69 53.28 11.79 52.84 12.01 52.49C12.33 51.95 12.9101 51.61 13.5401 51.61C14.2101 51.61 14.9301 52.04 15.1701 52.69C15.5101 53.62 15.34 54.66 15.26 55.63C15.21 56.19 15.16 56.75 15.1 57.31C15.01 58.19 14.18 58.84 13.33 58.84C13.25 58.85 13.17 58.85 13.1 58.84Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M17.8499 62.16C17.8999 60.94 18.1 59.72 18.26 58.52C18.42 57.37 18.68 56.22 18.92 55.08C18.9 55.16 18.89 55.23 18.87 55.31C18.95 54.92 19.05 54.52 19.14 54.13C19.29 53.49 19.4299 52.84 19.7099 52.24C19.9399 51.75 20.34 51.37 20.87 51.22C21.46 51.06 22.1699 51.21 22.5899 51.67C22.9199 52.03 23.11 52.45 23.11 52.94C23.11 53.24 23.03 53.53 22.9 53.78C22.67 54.5 22.5099 55.25 22.3399 55.98C22.2299 56.53 22.12 57.08 22 57.62C22.02 57.55 22.04 57.47 22.05 57.39C21.74 58.92 21.57 60.47 21.4 62.02C21.4 62.07 21.4 62.11 21.39 62.16C21.35 63.12 20.62 63.93 19.62 63.93C18.69 63.93 17.8099 63.13 17.8499 62.16Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path d="M22.3399 55.98C22.3399 55.98 22.34 55.99 22.34 56C22.33 55.99 22.3399 55.99 22.3399 55.98Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M41.11 35C41.09 34.8 41.06 34.59 41.03 34.39C40.71 34.07 40.51 33.63 40.51 33.15C40.51 32.19 41.32 31.38 42.28 31.38C42.92 31.38 43.5301 31.61 43.9301 32.13C44.4501 32.8 44.51 33.7 44.61 34.52C44.73 35.48 44.06 36.38 43.09 36.51C43.02 36.52 42.94 36.53 42.86 36.53C42.01 36.53 41.22 35.88 41.11 35Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M47.63 43.11C46.66 42.98 46 42.07 46.11 41.11C46.22 40.2 46.31 39.29 46.4 38.38C46.45 37.49 46.4799 36.6 46.45 35.71C46.11 35.39 45.9 34.93 45.9 34.43C45.9 33.93 45.99 33.39 46.2 32.95C46.7 31.88 47.95 31.57 48.91 32.24C49.41 32.59 49.73 33.1199 49.83 33.7299C49.93 34.3899 50 35.07 50.01 35.75C50.01 36.36 50.03 36.96 49.99 37.57C49.91 38.92 49.79 40.27 49.62 41.61C49.51 42.49 48.71 43.14 47.85 43.14C47.78 43.13 47.7 43.13 47.63 43.11Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M61.63 13.54C61.63 13.2 61.64 12.86 61.64 12.53C61.65 12.13 61.6299 11.71 61.6999 11.32C61.7999 10.78 62.08 10.31 62.56 10.03C63.02 9.76003 63.65 9.68999 64.14 9.92999C64.64 10.16 65.03 10.57 65.17 11.11C65.24 11.38 65.2499 11.66 65.1899 11.92C65.1699 12.46 65.17 13 65.16 13.54C65.15 14.5 64.36 15.31 63.39 15.31C62.44 15.31 61.61 14.51 61.63 13.54Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M67.99 19.39C67.99 18.62 68.08 17.87 68.22 17.12C68.22 17.1 68.23 17.08 68.23 17.06C68.24 17.02 68.25 16.98 68.25 16.94C68.24 16.97 68.24 17 68.23 17.03C68.32 16.62 68.4 16.21 68.48 15.8C68.46 15.88 68.4501 15.95 68.4301 16.03C68.4601 15.9 68.48 15.76 68.51 15.63C68.49 15.71 68.48 15.78 68.46 15.86C68.63 15.01 68.84 14.16 69.04 13.32C69.18 12.74 69.32 12.16 69.45 11.57C69.6499 10.75 69.77 9.86999 70.17 9.11999C70.51 8.47999 71.2499 8.2 71.9399 8.26C71.9499 8.26 71.96 8.26 71.97 8.26C72.63 8.32 73.2901 8.88998 73.4301 9.54998C73.4801 9.75998 73.51 9.94998 73.51 10.17C73.51 10.54 73.3899 10.89 73.1899 11.17C72.9499 12.2 72.6799 13.22 72.4399 14.25C72.2699 14.97 72.1099 15.69 71.9399 16.41C71.9399 16.43 71.9301 16.45 71.9301 16.46C71.9301 16.47 71.93 16.48 71.92 16.5C71.91 16.54 71.9 16.57 71.9 16.61C71.84 16.93 71.77 17.25 71.7 17.56C71.6899 17.61 71.68 17.66 71.67 17.71C71.67 17.72 71.67 17.73 71.67 17.73C71.67 17.74 71.67 17.75 71.67 17.76C71.6 18.12 71.55 18.48 71.51 18.85C71.51 19.03 71.5 19.21 71.5 19.39C71.5 20.35 70.69 21.16 69.73 21.16C68.8 21.16 68 20.36 67.99 19.39Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M71.74 17.56C71.74 17.55 71.75 17.55 71.74 17.56C71.74 17.56 71.74 17.58 71.74 17.59C71.74 17.58 71.74 17.57 71.74 17.56Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
<path
|
||||
d="M68.23 17.1C68.23 17.11 68.23 17.12 68.23 17.12C68.23 17.14 68.22 17.16 68.22 17.17C68.22 17.15 68.23 17.12 68.23 17.1Z"
|
||||
fill="rgba(191, 192, 191, 1)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 18 KiB |