ref: change printWidth to 100 & re-format
This commit is contained in:
parent
e3c416583a
commit
1d0a165723
@ -2,4 +2,4 @@ export const SECOND = 1000;
|
||||
export const MINUTE = 60 * SECOND;
|
||||
export const HOUR = 60 * MINUTE;
|
||||
export const DAY = 24 * HOUR;
|
||||
export const WEEK = 7 * DAY;
|
||||
export const WEEK = 7 * DAY;
|
||||
|
||||
@ -5,4 +5,4 @@ export const sql = postgres(postgresConfig);
|
||||
|
||||
export const sqlCred = postgres(postgresConfigCred);
|
||||
|
||||
export const sqlTest = postgres(postgresConfig);
|
||||
export const sqlTest = postgres(postgresConfig);
|
||||
|
||||
@ -4,7 +4,7 @@ const host = process.env.REDIS_HOST || "localhost";
|
||||
const port = parseInt(process.env.REDIS_PORT) || 6379;
|
||||
|
||||
export const redis = new Redis({
|
||||
port: port,
|
||||
host: host,
|
||||
maxRetriesPerRequest: null,
|
||||
port: port,
|
||||
host: host,
|
||||
maxRetriesPerRequest: null
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,13 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1758438506680,
|
||||
"tag": "0000_aspiring_mikhail_rasputin",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1758438506680,
|
||||
"tag": "0000_aspiring_mikhail_rasputin",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,3 +1,2 @@
|
||||
import { relations } from "drizzle-orm/relations";
|
||||
import { } from "./schema";
|
||||
|
||||
import {} from "./schema";
|
||||
|
||||
@ -1,183 +1,329 @@
|
||||
import { pgTable, uniqueIndex, index, integer, bigint, varchar, text, timestamp, smallint, boolean, unique, serial, bigserial, uuid, pgSequence } from "drizzle-orm/pg-core"
|
||||
import { sql } from "drizzle-orm"
|
||||
import {
|
||||
pgTable,
|
||||
uniqueIndex,
|
||||
index,
|
||||
integer,
|
||||
bigint,
|
||||
varchar,
|
||||
text,
|
||||
timestamp,
|
||||
smallint,
|
||||
boolean,
|
||||
unique,
|
||||
serial,
|
||||
bigserial,
|
||||
uuid,
|
||||
pgSequence
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { sql } from "drizzle-orm";
|
||||
|
||||
export const allDataIdSeq = pgSequence("all_data_id_seq", {
|
||||
startWith: "1",
|
||||
increment: "1",
|
||||
minValue: "1",
|
||||
maxValue: "2147483647",
|
||||
cache: "1",
|
||||
cycle: false
|
||||
});
|
||||
export const labelingResultIdSeq = pgSequence("labeling_result_id_seq", {
|
||||
startWith: "1",
|
||||
increment: "1",
|
||||
minValue: "1",
|
||||
maxValue: "2147483647",
|
||||
cache: "1",
|
||||
cycle: false
|
||||
});
|
||||
export const songsIdSeq = pgSequence("songs_id_seq", {
|
||||
startWith: "1",
|
||||
increment: "1",
|
||||
minValue: "1",
|
||||
maxValue: "2147483647",
|
||||
cache: "1",
|
||||
cycle: false
|
||||
});
|
||||
export const videoSnapshotIdSeq = pgSequence("video_snapshot_id_seq", {
|
||||
startWith: "1",
|
||||
increment: "1",
|
||||
minValue: "1",
|
||||
maxValue: "2147483647",
|
||||
cache: "1",
|
||||
cycle: false
|
||||
});
|
||||
export const viewsIncrementRateIdSeq = pgSequence("views_increment_rate_id_seq", {
|
||||
startWith: "1",
|
||||
increment: "1",
|
||||
minValue: "1",
|
||||
maxValue: "9223372036854775807",
|
||||
cache: "1",
|
||||
cycle: false
|
||||
});
|
||||
|
||||
export const allDataIdSeq = pgSequence("all_data_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
|
||||
export const labelingResultIdSeq = pgSequence("labeling_result_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
|
||||
export const songsIdSeq = pgSequence("songs_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
|
||||
export const videoSnapshotIdSeq = pgSequence("video_snapshot_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "2147483647", cache: "1", cycle: false })
|
||||
export const viewsIncrementRateIdSeq = pgSequence("views_increment_rate_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false })
|
||||
export const bilibiliMetadata = pgTable(
|
||||
"bilibili_metadata",
|
||||
{
|
||||
id: integer()
|
||||
.default(sql`nextval('all_data_id_seq'::regclass)`)
|
||||
.notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
bvid: varchar({ length: 12 }),
|
||||
description: text(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
uid: bigint({ mode: "number" }),
|
||||
tags: text(),
|
||||
title: text(),
|
||||
publishedAt: timestamp("published_at", { withTimezone: true, mode: "string" }),
|
||||
duration: integer(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" }).default(sql`CURRENT_TIMESTAMP`),
|
||||
status: integer().default(0).notNull(),
|
||||
coverUrl: text("cover_url")
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex("all_data_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
|
||||
index("idx_all-data_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_all-data_bvid").using("btree", table.bvid.asc().nullsLast().op("text_ops")),
|
||||
index("idx_all-data_uid").using("btree", table.uid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_bili-meta_status").using("btree", table.status.asc().nullsLast().op("int4_ops")),
|
||||
uniqueIndex("unq_all-data_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops"))
|
||||
]
|
||||
);
|
||||
|
||||
export const bilibiliMetadata = pgTable("bilibili_metadata", {
|
||||
id: integer().default(sql`nextval('all_data_id_seq'::regclass)`).notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
bvid: varchar({ length: 12 }),
|
||||
description: text(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
uid: bigint({ mode: "number" }),
|
||||
tags: text(),
|
||||
title: text(),
|
||||
publishedAt: timestamp("published_at", { withTimezone: true, mode: 'string' }),
|
||||
duration: integer(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`),
|
||||
status: integer().default(0).notNull(),
|
||||
coverUrl: text("cover_url"),
|
||||
}, (table) => [
|
||||
uniqueIndex("all_data_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
|
||||
index("idx_all-data_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_all-data_bvid").using("btree", table.bvid.asc().nullsLast().op("text_ops")),
|
||||
index("idx_all-data_uid").using("btree", table.uid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_bili-meta_status").using("btree", table.status.asc().nullsLast().op("int4_ops")),
|
||||
uniqueIndex("unq_all-data_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
]);
|
||||
export const labellingResult = pgTable(
|
||||
"labelling_result",
|
||||
{
|
||||
id: integer()
|
||||
.default(sql`nextval('labeling_result_id_seq'::regclass)`)
|
||||
.notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
label: smallint().notNull(),
|
||||
modelVersion: text("model_version").notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
logits: smallint().array()
|
||||
},
|
||||
(table) => [
|
||||
index("idx_labeling_label_model-version").using(
|
||||
"btree",
|
||||
table.label.asc().nullsLast().op("int2_ops"),
|
||||
table.modelVersion.asc().nullsLast().op("int2_ops")
|
||||
),
|
||||
index("idx_labeling_model-version").using("btree", table.modelVersion.asc().nullsLast().op("text_ops")),
|
||||
index("idx_labelling_aid-label").using(
|
||||
"btree",
|
||||
table.aid.asc().nullsLast().op("int2_ops"),
|
||||
table.label.asc().nullsLast().op("int2_ops")
|
||||
),
|
||||
uniqueIndex("labeling_result_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
|
||||
uniqueIndex("unq_labelling-result_aid_model-version").using(
|
||||
"btree",
|
||||
table.aid.asc().nullsLast().op("int8_ops"),
|
||||
table.modelVersion.asc().nullsLast().op("int8_ops")
|
||||
)
|
||||
]
|
||||
);
|
||||
|
||||
export const labellingResult = pgTable("labelling_result", {
|
||||
id: integer().default(sql`nextval('labeling_result_id_seq'::regclass)`).notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
label: smallint().notNull(),
|
||||
modelVersion: text("model_version").notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
logits: smallint().array(),
|
||||
}, (table) => [
|
||||
index("idx_labeling_label_model-version").using("btree", table.label.asc().nullsLast().op("int2_ops"), table.modelVersion.asc().nullsLast().op("int2_ops")),
|
||||
index("idx_labeling_model-version").using("btree", table.modelVersion.asc().nullsLast().op("text_ops")),
|
||||
index("idx_labelling_aid-label").using("btree", table.aid.asc().nullsLast().op("int2_ops"), table.label.asc().nullsLast().op("int2_ops")),
|
||||
uniqueIndex("labeling_result_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
|
||||
uniqueIndex("unq_labelling-result_aid_model-version").using("btree", table.aid.asc().nullsLast().op("int8_ops"), table.modelVersion.asc().nullsLast().op("int8_ops")),
|
||||
]);
|
||||
export const latestVideoSnapshot = pgTable(
|
||||
"latest_video_snapshot",
|
||||
{
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).primaryKey().notNull(),
|
||||
time: timestamp({ withTimezone: true, mode: "string" }).notNull(),
|
||||
views: integer().notNull(),
|
||||
coins: integer().notNull(),
|
||||
likes: integer().notNull(),
|
||||
favorites: integer().notNull(),
|
||||
replies: integer().notNull(),
|
||||
danmakus: integer().notNull(),
|
||||
shares: integer().notNull()
|
||||
},
|
||||
(table) => [
|
||||
index("idx_latest-video-snapshot_time").using("btree", table.time.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_latest-video-snapshot_views").using("btree", table.views.asc().nullsLast().op("int4_ops"))
|
||||
]
|
||||
);
|
||||
|
||||
export const latestVideoSnapshot = pgTable("latest_video_snapshot", {
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).primaryKey().notNull(),
|
||||
time: timestamp({ withTimezone: true, mode: 'string' }).notNull(),
|
||||
views: integer().notNull(),
|
||||
coins: integer().notNull(),
|
||||
likes: integer().notNull(),
|
||||
favorites: integer().notNull(),
|
||||
replies: integer().notNull(),
|
||||
danmakus: integer().notNull(),
|
||||
shares: integer().notNull(),
|
||||
}, (table) => [
|
||||
index("idx_latest-video-snapshot_time").using("btree", table.time.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_latest-video-snapshot_views").using("btree", table.views.asc().nullsLast().op("int4_ops")),
|
||||
]);
|
||||
export const videoSnapshot = pgTable(
|
||||
"video_snapshot",
|
||||
{
|
||||
id: integer()
|
||||
.default(sql`nextval('video_snapshot_id_seq'::regclass)`)
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
views: integer().notNull(),
|
||||
coins: integer().notNull(),
|
||||
likes: integer().notNull(),
|
||||
favorites: integer().notNull(),
|
||||
shares: integer().notNull(),
|
||||
danmakus: integer().notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
replies: integer().notNull()
|
||||
},
|
||||
(table) => [
|
||||
index("idx_vid_snapshot_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_vid_snapshot_aid_created_at").using(
|
||||
"btree",
|
||||
table.aid.asc().nullsLast().op("timestamptz_ops"),
|
||||
table.createdAt.asc().nullsLast().op("timestamptz_ops")
|
||||
),
|
||||
index("idx_vid_snapshot_time").using("btree", table.createdAt.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_vid_snapshot_views").using("btree", table.views.asc().nullsLast().op("int4_ops")),
|
||||
uniqueIndex("video_snapshot_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops"))
|
||||
]
|
||||
);
|
||||
|
||||
export const videoSnapshot = pgTable("video_snapshot", {
|
||||
id: integer().default(sql`nextval('video_snapshot_id_seq'::regclass)`).notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
views: integer().notNull(),
|
||||
coins: integer().notNull(),
|
||||
likes: integer().notNull(),
|
||||
favorites: integer().notNull(),
|
||||
shares: integer().notNull(),
|
||||
danmakus: integer().notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
replies: integer().notNull(),
|
||||
}, (table) => [
|
||||
index("idx_vid_snapshot_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_vid_snapshot_aid_created_at").using("btree", table.aid.asc().nullsLast().op("timestamptz_ops"), table.createdAt.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_vid_snapshot_time").using("btree", table.createdAt.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_vid_snapshot_views").using("btree", table.views.asc().nullsLast().op("int4_ops")),
|
||||
uniqueIndex("video_snapshot_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
|
||||
]);
|
||||
export const songs = pgTable(
|
||||
"songs",
|
||||
{
|
||||
id: integer()
|
||||
.default(sql`nextval('songs_id_seq'::regclass)`)
|
||||
.notNull(),
|
||||
name: text(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }),
|
||||
publishedAt: timestamp("published_at", { withTimezone: true, mode: "string" }),
|
||||
duration: integer(),
|
||||
type: smallint(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
neteaseId: bigint("netease_id", { mode: "number" }),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
deleted: boolean().default(false).notNull(),
|
||||
image: text(),
|
||||
producer: text()
|
||||
},
|
||||
(table) => [
|
||||
index("idx_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_hash_songs_aid").using("hash", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_netease_id").using("btree", table.neteaseId.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_published_at").using("btree", table.publishedAt.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_type").using("btree", table.type.asc().nullsLast().op("int2_ops")),
|
||||
uniqueIndex("songs_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
|
||||
uniqueIndex("unq_songs_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
uniqueIndex("unq_songs_netease_id").using("btree", table.neteaseId.asc().nullsLast().op("int8_ops"))
|
||||
]
|
||||
);
|
||||
|
||||
export const songs = pgTable("songs", {
|
||||
id: integer().default(sql`nextval('songs_id_seq'::regclass)`).notNull(),
|
||||
name: text(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }),
|
||||
publishedAt: timestamp("published_at", { withTimezone: true, mode: 'string' }),
|
||||
duration: integer(),
|
||||
type: smallint(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
neteaseId: bigint("netease_id", { mode: "number" }),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
deleted: boolean().default(false).notNull(),
|
||||
image: text(),
|
||||
producer: text(),
|
||||
}, (table) => [
|
||||
index("idx_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_hash_songs_aid").using("hash", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_netease_id").using("btree", table.neteaseId.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_published_at").using("btree", table.publishedAt.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_type").using("btree", table.type.asc().nullsLast().op("int2_ops")),
|
||||
uniqueIndex("songs_pkey").using("btree", table.id.asc().nullsLast().op("int4_ops")),
|
||||
uniqueIndex("unq_songs_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
uniqueIndex("unq_songs_netease_id").using("btree", table.neteaseId.asc().nullsLast().op("int8_ops")),
|
||||
]);
|
||||
|
||||
export const bilibiliUser = pgTable("bilibili_user", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
uid: bigint({ mode: "number" }).notNull(),
|
||||
username: text().notNull(),
|
||||
desc: text().notNull(),
|
||||
fans: integer().notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
}, (table) => [
|
||||
index("idx_bili-user_uid").using("btree", table.uid.asc().nullsLast().op("int8_ops")),
|
||||
unique("unq_bili-user_uid").on(table.uid),
|
||||
]);
|
||||
export const bilibiliUser = pgTable(
|
||||
"bilibili_user",
|
||||
{
|
||||
id: serial().primaryKey().notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
uid: bigint({ mode: "number" }).notNull(),
|
||||
username: text().notNull(),
|
||||
desc: text().notNull(),
|
||||
fans: integer().notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull()
|
||||
},
|
||||
(table) => [
|
||||
index("idx_bili-user_uid").using("btree", table.uid.asc().nullsLast().op("int8_ops")),
|
||||
unique("unq_bili-user_uid").on(table.uid)
|
||||
]
|
||||
);
|
||||
|
||||
export const singer = pgTable("singer", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
name: text().notNull(),
|
||||
name: text().notNull()
|
||||
});
|
||||
|
||||
export const relations = pgTable("relations", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
sourceId: bigint("source_id", { mode: "number" }).notNull(),
|
||||
sourceType: text("source_type").notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
targetId: bigint("target_id", { mode: "number" }).notNull(),
|
||||
targetType: text("target_type").notNull(),
|
||||
relation: text().notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
}, (table) => [
|
||||
index("idx_relations_source_id_source_type_relation").using("btree", table.sourceId.asc().nullsLast().op("int8_ops"), table.sourceType.asc().nullsLast().op("int8_ops"), table.relation.asc().nullsLast().op("text_ops")),
|
||||
index("idx_relations_target_id_target_type_relation").using("btree", table.targetId.asc().nullsLast().op("text_ops"), table.targetType.asc().nullsLast().op("text_ops"), table.relation.asc().nullsLast().op("text_ops")),
|
||||
unique("unq_relations").on(table.sourceId, table.sourceType, table.targetId, table.targetType, table.relation),
|
||||
]);
|
||||
export const relations = pgTable(
|
||||
"relations",
|
||||
{
|
||||
id: serial().primaryKey().notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
sourceId: bigint("source_id", { mode: "number" }).notNull(),
|
||||
sourceType: text("source_type").notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
targetId: bigint("target_id", { mode: "number" }).notNull(),
|
||||
targetType: text("target_type").notNull(),
|
||||
relation: text().notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull()
|
||||
},
|
||||
(table) => [
|
||||
index("idx_relations_source_id_source_type_relation").using(
|
||||
"btree",
|
||||
table.sourceId.asc().nullsLast().op("int8_ops"),
|
||||
table.sourceType.asc().nullsLast().op("int8_ops"),
|
||||
table.relation.asc().nullsLast().op("text_ops")
|
||||
),
|
||||
index("idx_relations_target_id_target_type_relation").using(
|
||||
"btree",
|
||||
table.targetId.asc().nullsLast().op("text_ops"),
|
||||
table.targetType.asc().nullsLast().op("text_ops"),
|
||||
table.relation.asc().nullsLast().op("text_ops")
|
||||
),
|
||||
unique("unq_relations").on(table.sourceId, table.sourceType, table.targetId, table.targetType, table.relation)
|
||||
]
|
||||
);
|
||||
|
||||
export const globalKv = pgTable("global_kv", {
|
||||
key: text().primaryKey().notNull(),
|
||||
value: text().notNull(),
|
||||
value: text().notNull()
|
||||
});
|
||||
|
||||
export const snapshotSchedule = pgTable("snapshot_schedule", {
|
||||
id: bigserial({ mode: "bigint" }).notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
type: text(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
startedAt: timestamp("started_at", { withTimezone: true, mode: 'string' }),
|
||||
finishedAt: timestamp("finished_at", { withTimezone: true, mode: 'string' }),
|
||||
status: text().default('pending').notNull(),
|
||||
}, (table) => [
|
||||
index("idx_snapshot_schedule_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_snapshot_schedule_started_at").using("btree", table.startedAt.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_snapshot_schedule_status").using("btree", table.status.asc().nullsLast().op("text_ops")),
|
||||
index("idx_snapshot_schedule_type").using("btree", table.type.asc().nullsLast().op("text_ops")),
|
||||
uniqueIndex("snapshot_schedule_pkey").using("btree", table.id.asc().nullsLast().op("int8_ops")),
|
||||
]);
|
||||
export const snapshotSchedule = pgTable(
|
||||
"snapshot_schedule",
|
||||
{
|
||||
id: bigserial({ mode: "bigint" }).notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
type: text(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
startedAt: timestamp("started_at", { withTimezone: true, mode: "string" }),
|
||||
finishedAt: timestamp("finished_at", { withTimezone: true, mode: "string" }),
|
||||
status: text().default("pending").notNull()
|
||||
},
|
||||
(table) => [
|
||||
index("idx_snapshot_schedule_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_snapshot_schedule_started_at").using(
|
||||
"btree",
|
||||
table.startedAt.asc().nullsLast().op("timestamptz_ops")
|
||||
),
|
||||
index("idx_snapshot_schedule_status").using("btree", table.status.asc().nullsLast().op("text_ops")),
|
||||
index("idx_snapshot_schedule_type").using("btree", table.type.asc().nullsLast().op("text_ops")),
|
||||
uniqueIndex("snapshot_schedule_pkey").using("btree", table.id.asc().nullsLast().op("int8_ops"))
|
||||
]
|
||||
);
|
||||
|
||||
export const classifiedLabelsHuman = pgTable("classified_labels_human", {
|
||||
id: serial().primaryKey().notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
author: uuid().notNull(),
|
||||
label: smallint().notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
||||
}, (table) => [
|
||||
index("idx_classified-labels-human_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_classified-labels-human_author").using("btree", table.author.asc().nullsLast().op("uuid_ops")),
|
||||
index("idx_classified-labels-human_created-at").using("btree", table.createdAt.asc().nullsLast().op("timestamptz_ops")),
|
||||
index("idx_classified-labels-human_label").using("btree", table.label.asc().nullsLast().op("int2_ops")),
|
||||
]);
|
||||
export const classifiedLabelsHuman = pgTable(
|
||||
"classified_labels_human",
|
||||
{
|
||||
id: serial().primaryKey().notNull(),
|
||||
// You can use { mode: "bigint" } if numbers are exceeding js number limitations
|
||||
aid: bigint({ mode: "number" }).notNull(),
|
||||
author: uuid().notNull(),
|
||||
label: smallint().notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true, mode: "string" })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull()
|
||||
},
|
||||
(table) => [
|
||||
index("idx_classified-labels-human_aid").using("btree", table.aid.asc().nullsLast().op("int8_ops")),
|
||||
index("idx_classified-labels-human_author").using("btree", table.author.asc().nullsLast().op("uuid_ops")),
|
||||
index("idx_classified-labels-human_created-at").using(
|
||||
"btree",
|
||||
table.createdAt.asc().nullsLast().op("timestamptz_ops")
|
||||
),
|
||||
index("idx_classified-labels-human_label").using("btree", table.label.asc().nullsLast().op("int2_ops"))
|
||||
]
|
||||
);
|
||||
|
||||
2
packages/core/drizzle/outerSchema.d.ts
vendored
2
packages/core/drizzle/outerSchema.d.ts
vendored
@ -7,4 +7,4 @@ export type SensitiveUserFields = "password" | "unqId";
|
||||
export type BilibiliMetadataType = InferSelectModel<typeof bilibiliMetadata>;
|
||||
export type VideoSnapshotType = InferSelectModel<typeof videoSnapshot>;
|
||||
export type LatestVideoSnapshotType = InferSelectModel<typeof latestVideoSnapshot>;
|
||||
export type SongType = InferSelectModel<typeof songs>;
|
||||
export type SongType = InferSelectModel<typeof songs>;
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
export function generateRandomId(length: number): string {
|
||||
const characters = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
||||
const characters = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
const charactersLength = characters.length;
|
||||
const randomBytes = new Uint8Array(length);
|
||||
|
||||
crypto.getRandomValues(randomBytes);
|
||||
|
||||
let result = '';
|
||||
let result = "";
|
||||
for (let i = 0; i < length; i++) {
|
||||
const randomIndex = randomBytes[i] % charactersLength;
|
||||
result += characters.charAt(randomIndex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ const createTransport = (level: string, filename: string) => {
|
||||
maxsize,
|
||||
tailable,
|
||||
maxFiles,
|
||||
format: format.combine(timestampFormat, format.json({ replacer })),
|
||||
format: format.combine(timestampFormat, format.json({ replacer }))
|
||||
});
|
||||
};
|
||||
|
||||
@ -65,13 +65,13 @@ const winstonLogger = winston.createLogger({
|
||||
format.timestamp({ format: "YYYY-MM-DD HH:mm:ss.SSS" }),
|
||||
format.colorize(),
|
||||
format.errors({ stack: true }),
|
||||
customFormat,
|
||||
),
|
||||
customFormat
|
||||
)
|
||||
}),
|
||||
createTransport("silly", sillyLogPath),
|
||||
createTransport("warn", warnLogPath),
|
||||
createTransport("error", errorLogPath),
|
||||
],
|
||||
createTransport("error", errorLogPath)
|
||||
]
|
||||
});
|
||||
|
||||
const logger = {
|
||||
@ -96,7 +96,7 @@ const logger = {
|
||||
} else {
|
||||
winstonLogger.error(error, { service, codePath });
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default logger;
|
||||
|
||||
@ -2,54 +2,51 @@ import { RateLimiter as Limiter } from "@koshnic/ratelimit";
|
||||
import { redis } from "@core/db/redis.ts";
|
||||
|
||||
export interface RateLimiterConfig {
|
||||
duration: number;
|
||||
max: number;
|
||||
duration: number;
|
||||
max: number;
|
||||
}
|
||||
|
||||
export class RateLimiterError extends Error {
|
||||
public code: string;
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "RateLimiterError";
|
||||
this.code = "RATE_LIMIT_EXCEEDED";
|
||||
}
|
||||
public code: string;
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "RateLimiterError";
|
||||
this.code = "RATE_LIMIT_EXCEEDED";
|
||||
}
|
||||
}
|
||||
|
||||
export class MultipleRateLimiter {
|
||||
private readonly name: string;
|
||||
private readonly configs: RateLimiterConfig[] = [];
|
||||
private readonly limiter: Limiter;
|
||||
private readonly name: string;
|
||||
private readonly configs: RateLimiterConfig[] = [];
|
||||
private readonly limiter: Limiter;
|
||||
|
||||
/*
|
||||
* @param name The name of the rate limiter
|
||||
* @param configs The configuration of the rate limiter, containing:
|
||||
* - duration: The duration of window in seconds
|
||||
* - max: The maximum number of tokens allowed in the window
|
||||
*/
|
||||
constructor(
|
||||
name: string,
|
||||
configs: RateLimiterConfig[]
|
||||
) {
|
||||
this.configs = configs;
|
||||
this.limiter = new Limiter(redis);
|
||||
this.name = name;
|
||||
}
|
||||
/*
|
||||
* @param name The name of the rate limiter
|
||||
* @param configs The configuration of the rate limiter, containing:
|
||||
* - duration: The duration of window in seconds
|
||||
* - max: The maximum number of tokens allowed in the window
|
||||
*/
|
||||
constructor(name: string, configs: RateLimiterConfig[]) {
|
||||
this.configs = configs;
|
||||
this.limiter = new Limiter(redis);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger an event in the rate limiter
|
||||
*/
|
||||
async trigger(shouldThrow = true): Promise<void> {
|
||||
for (let i = 0; i < this.configs.length; i++) {
|
||||
const { duration, max } = this.configs[i];
|
||||
const { allowed } = await this.limiter.allow(`cvsa:${this.name}_${i}`, {
|
||||
burst: max,
|
||||
ratePerPeriod: max,
|
||||
period: duration,
|
||||
cost: 1
|
||||
});
|
||||
if (!allowed && shouldThrow) {
|
||||
throw new RateLimiterError("Rate limit exceeded")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Trigger an event in the rate limiter
|
||||
*/
|
||||
async trigger(shouldThrow = true): Promise<void> {
|
||||
for (let i = 0; i < this.configs.length; i++) {
|
||||
const { duration, max } = this.configs[i];
|
||||
const { allowed } = await this.limiter.allow(`cvsa:${this.name}_${i}`, {
|
||||
burst: max,
|
||||
ratePerPeriod: max,
|
||||
period: duration,
|
||||
cost: 1
|
||||
});
|
||||
if (!allowed && shouldThrow) {
|
||||
throw new RateLimiterError("Rate limit exceeded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,4 +54,4 @@ export class SlidingWindow {
|
||||
const key = `cvsa:sliding_window:${eventName}`;
|
||||
return this.redis.del(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import { spawn, SpawnOptions } from "child_process";
|
||||
export function spawnPromise(
|
||||
command: string,
|
||||
args: string[] = [],
|
||||
options?: SpawnOptions,
|
||||
options?: SpawnOptions
|
||||
): Promise<{ stdout: string; stderr: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, options);
|
||||
@ -171,8 +171,7 @@ class NetworkDelegate {
|
||||
for (const proxyName of shuffleArray(proxiesNames)) {
|
||||
try {
|
||||
return await this.proxyRequest<R>(url, proxyName, task, method);
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
if (e instanceof RateLimiterError) {
|
||||
continue;
|
||||
}
|
||||
@ -202,7 +201,7 @@ class NetworkDelegate {
|
||||
proxyName: string,
|
||||
task: string,
|
||||
method: string = "GET",
|
||||
force: boolean = false,
|
||||
force: boolean = false
|
||||
): Promise<R> {
|
||||
const proxy = this.proxies[proxyName];
|
||||
if (!proxy) {
|
||||
@ -232,7 +231,7 @@ class NetworkDelegate {
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
signal: controller.signal,
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
clearTimeout(timeout);
|
||||
@ -262,7 +261,7 @@ class NetworkDelegate {
|
||||
"--connect-timeout",
|
||||
"10",
|
||||
"--profile",
|
||||
`CVSA-${region}`,
|
||||
`CVSA-${region}`
|
||||
]);
|
||||
const out = output.stdout;
|
||||
const rawData = JSON.parse(out);
|
||||
@ -270,7 +269,7 @@ class NetworkDelegate {
|
||||
// noinspection ExceptionCaughtLocallyJS
|
||||
throw new NetSchedulerError(
|
||||
`Error proxying ${url} to ali-fc region ${region}, code: ${rawData.statusCode}.`,
|
||||
"ALICLOUD_PROXY_ERR",
|
||||
"ALICLOUD_PROXY_ERR"
|
||||
);
|
||||
} else {
|
||||
return JSON.parse(rawData.body) as R;
|
||||
@ -280,7 +279,7 @@ class NetworkDelegate {
|
||||
throw new NetSchedulerError(
|
||||
`Unhandled error: Cannot proxy ${url} to ali-fc-${region}.`,
|
||||
"ALICLOUD_PROXY_ERR",
|
||||
e,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -290,38 +289,38 @@ const networkDelegate = new NetworkDelegate();
|
||||
const videoInfoRateLimiterConfig: RateLimiterConfig[] = [
|
||||
{
|
||||
duration: 0.3,
|
||||
max: 1,
|
||||
max: 1
|
||||
},
|
||||
{
|
||||
duration: 3,
|
||||
max: 5,
|
||||
max: 5
|
||||
},
|
||||
{
|
||||
duration: 30,
|
||||
max: 30,
|
||||
max: 30
|
||||
},
|
||||
{
|
||||
duration: 2 * 60,
|
||||
max: 50,
|
||||
},
|
||||
max: 50
|
||||
}
|
||||
];
|
||||
const biliLimiterConfig: RateLimiterConfig[] = [
|
||||
{
|
||||
duration: 1,
|
||||
max: 6,
|
||||
max: 6
|
||||
},
|
||||
{
|
||||
duration: 5,
|
||||
max: 20,
|
||||
max: 20
|
||||
},
|
||||
{
|
||||
duration: 30,
|
||||
max: 100,
|
||||
max: 100
|
||||
},
|
||||
{
|
||||
duration: 5 * 60,
|
||||
max: 200,
|
||||
},
|
||||
max: 200
|
||||
}
|
||||
];
|
||||
|
||||
const bili_test = [...biliLimiterConfig];
|
||||
@ -369,7 +368,7 @@ networkDelegate.addTask("getLatestVideos", "bilibili", "all");
|
||||
networkDelegate.addTask(
|
||||
"snapshotMilestoneVideo",
|
||||
"bilibili",
|
||||
regions.map((region) => `alicloud-${region}`),
|
||||
regions.map((region) => `alicloud-${region}`)
|
||||
);
|
||||
networkDelegate.addTask("snapshotVideo", "bili_test", [
|
||||
"alicloud-qingdao",
|
||||
@ -377,7 +376,7 @@ networkDelegate.addTask("snapshotVideo", "bili_test", [
|
||||
"alicloud-zhangjiakou",
|
||||
"alicloud-chengdu",
|
||||
"alicloud-shenzhen",
|
||||
"alicloud-hohhot",
|
||||
"alicloud-hohhot"
|
||||
]);
|
||||
networkDelegate.addTask("bulkSnapshot", "bili_strict", [
|
||||
"alicloud-qingdao",
|
||||
@ -385,7 +384,7 @@ networkDelegate.addTask("bulkSnapshot", "bili_strict", [
|
||||
"alicloud-zhangjiakou",
|
||||
"alicloud-chengdu",
|
||||
"alicloud-shenzhen",
|
||||
"alicloud-hohhot",
|
||||
"alicloud-hohhot"
|
||||
]);
|
||||
networkDelegate.setTaskLimiter("getVideoInfo", videoInfoRateLimiterConfig);
|
||||
networkDelegate.setTaskLimiter("getLatestVideos", null);
|
||||
|
||||
@ -53,7 +53,8 @@ export const rootHandler = new Elysia().get(
|
||||
},
|
||||
detail: {
|
||||
summary: "Root route",
|
||||
description: "The root path. It returns a JSON object containing a random virtual singer, \
|
||||
description:
|
||||
"The root path. It returns a JSON object containing a random virtual singer, \
|
||||
backend version, current server time and other miscellaneous information."
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +88,8 @@ export const getSongInfoHandler = new Elysia({ prefix: "/song" }).get(
|
||||
},
|
||||
detail: {
|
||||
summary: "Get information of a song",
|
||||
description: "This endpoint retrieves detailed information about a song using its unique ID, \
|
||||
description:
|
||||
"This endpoint retrieves detailed information about a song using its unique ID, \
|
||||
which can be provided in several formats. \
|
||||
The endpoint accepts a song ID in either a numerical format as the internal ID in our database\
|
||||
or as a bilibili video ID (either av or BV format). \
|
||||
|
||||
@ -9,20 +9,20 @@ import svelte from "@astrojs/svelte";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
|
||||
export default defineConfig({
|
||||
output: "server",
|
||||
adapter: node({
|
||||
mode: "standalone",
|
||||
}),
|
||||
integrations: [svelte()],
|
||||
vite: {
|
||||
server: {
|
||||
fs: {
|
||||
allow: [".", "../../"],
|
||||
},
|
||||
},
|
||||
plugins: [tsconfigPaths(), tailwindcss()],
|
||||
},
|
||||
markdown: {
|
||||
remarkRehype: { footnoteLabel: "脚注", footnoteBackLabel: "回到引用 1" },
|
||||
}
|
||||
});
|
||||
output: "server",
|
||||
adapter: node({
|
||||
mode: "standalone"
|
||||
}),
|
||||
integrations: [svelte()],
|
||||
vite: {
|
||||
server: {
|
||||
fs: {
|
||||
allow: [".", "../../"]
|
||||
}
|
||||
},
|
||||
plugins: [tsconfigPaths(), tailwindcss()]
|
||||
},
|
||||
markdown: {
|
||||
remarkRehype: { footnoteLabel: "脚注", footnoteBackLabel: "回到引用 1" }
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,25 +1,25 @@
|
||||
const N_1024 = BigInt(
|
||||
"129023318876534346704360951712586568674758913224876821534686030409476129469193481910786173836188085930974906857867802234113909470848523288588793477904039083513378341278558405407018889387577114155572311708428733260891448259786041525189132461448841652472631435226032063278124857443496954605482776113964107326943",
|
||||
"129023318876534346704360951712586568674758913224876821534686030409476129469193481910786173836188085930974906857867802234113909470848523288588793477904039083513378341278558405407018889387577114155572311708428733260891448259786041525189132461448841652472631435226032063278124857443496954605482776113964107326943"
|
||||
);
|
||||
|
||||
const N_2048 = BigInt(
|
||||
"23987552118069940970878653610463005981599204778388399885550631951871084945075866571231062435627294546200946516668493107358732376187241747090707087544153108117326163500579370560400058549184722138636116585329496684877258304519458316233517215780035360354808658620079068489084797380781488445517430961701007542207001544091884001098497324624368085682074645221148086075871342544591022944384890014176612259729018968864426602901247715051556212559854689574013699665035317257438297910516976812428036717668766321871780963854649899276251822244719887233041422346429752896925499321431273560130952088238625622570366815755926694833109",
|
||||
"23987552118069940970878653610463005981599204778388399885550631951871084945075866571231062435627294546200946516668493107358732376187241747090707087544153108117326163500579370560400058549184722138636116585329496684877258304519458316233517215780035360354808658620079068489084797380781488445517430961701007542207001544091884001098497324624368085682074645221148086075871342544591022944384890014176612259729018968864426602901247715051556212559854689574013699665035317257438297910516976812428036717668766321871780963854649899276251822244719887233041422346429752896925499321431273560130952088238625622570366815755926694833109"
|
||||
);
|
||||
|
||||
const N_1792 = BigInt(
|
||||
"23987552118069940970878653610463005981599204778388399885550631951871084945075866571231062435627294546200946516668493107358732376187241747090707087544153108117326163500579370560400058549184722138636116585329496684877258304519458316233517215780035360354808658620079068489084797380781488445517430961701007542207001544091884001098497324624368085682074645221148086075871342544591022944384890014176612259729018968864426602901247715051556212559854689574013699665035317257438297910516976812428036717668766321871780963854649899276251822244719887233041422346429752896925499321431273560130952088238625622570366815755926694833109",
|
||||
"23987552118069940970878653610463005981599204778388399885550631951871084945075866571231062435627294546200946516668493107358732376187241747090707087544153108117326163500579370560400058549184722138636116585329496684877258304519458316233517215780035360354808658620079068489084797380781488445517430961701007542207001544091884001098497324624368085682074645221148086075871342544591022944384890014176612259729018968864426602901247715051556212559854689574013699665035317257438297910516976812428036717668766321871780963854649899276251822244719887233041422346429752896925499321431273560130952088238625622570366815755926694833109"
|
||||
);
|
||||
|
||||
const N_1536 = BigInt(
|
||||
"1694330250214463438908848400950857073137355630337290254958754184668036770489801447652464038218330711288158361242955860326168191830448553710492926795708495297280933502917598985378231124113971732841791156356676046934277122699383776036675381503510992810963611269045078440132744168908318454891211962146563551929591147663448816841024591820348784855441153716551049843185172472891407933214238000452095646085222944171689449292644270516031799660928056315886939284985905227",
|
||||
"1694330250214463438908848400950857073137355630337290254958754184668036770489801447652464038218330711288158361242955860326168191830448553710492926795708495297280933502917598985378231124113971732841791156356676046934277122699383776036675381503510992810963611269045078440132744168908318454891211962146563551929591147663448816841024591820348784855441153716551049843185172472891407933214238000452095646085222944171689449292644270516031799660928056315886939284985905227"
|
||||
);
|
||||
|
||||
const N_3072 = BigInt(
|
||||
"4432919939296042464443862503456460073874727648022810391370558006281079088795179408238989283371442564716849343712703672836423961818025813387453469700639513190304802553045342607888612037304066433501317127429264242784608682213025490491212489901736408833027611579294436675682774458141490718959615677971745638214649336218217578937534746160749039668886450447773018369168258067682196337978245372237157696236362344796867228581553446331915147012787367438751646936429739232247148712001806846526947508445039707404287951727838234648917450736371192435665040644040487427986702098273581288935278964444790007953559851323281510927332862225214878776790605026472021669614552481167977412450477230442015077669503312683966631454347169703030544483487968842349634064181183599641180349414682042575010303056241481622837185325228233789954078775053744988023738762706404546546146837242590884760044438874357295029411988267287001033032827035809135092270843",
|
||||
"4432919939296042464443862503456460073874727648022810391370558006281079088795179408238989283371442564716849343712703672836423961818025813387453469700639513190304802553045342607888612037304066433501317127429264242784608682213025490491212489901736408833027611579294436675682774458141490718959615677971745638214649336218217578937534746160749039668886450447773018369168258067682196337978245372237157696236362344796867228581553446331915147012787367438751646936429739232247148712001806846526947508445039707404287951727838234648917450736371192435665040644040487427986702098273581288935278964444790007953559851323281510927332862225214878776790605026472021669614552481167977412450477230442015077669503312683966631454347169703030544483487968842349634064181183599641180349414682042575010303056241481622837185325228233789954078775053744988023738762706404546546146837242590884760044438874357295029411988267287001033032827035809135092270843"
|
||||
);
|
||||
|
||||
const N_4096 = BigInt(
|
||||
"703671044356805218391078271512201582198770553281951369783674142891088501340774249238173262580562112786670043634665390581120113644316651934154746357220932310140476300088580654571796404198410555061275065442553506658401183560336140989074165998202690496991174269748740565700402715364422506782445179963440819952745241176450402011121226863984008975377353558155910994380700267903933205531681076494639818328879475919332604951949178075254600102192323286738973253864238076198710173840170988339024438220034106150475640983877458155141500313471699516670799821379238743709125064098477109094533426340852518505385314780319279862586851512004686798362431227795743253799490998475141728082088984359237540124375439664236138519644100625154580910233437864328111620708697941949936338367445851449766581651338876219676721272448769082914348242483068204896479076062102236087066428603930888978596966798402915747531679758905013008059396214343112694563043918465373870648649652122703709658068801764236979191262744515840224548957285182453209028157886219424802426566456408109642062498413592155064289314088837031184200671561102160059065729282902863248815224399131391716503171191977463328439766546574118092303414702384104112719959325482439604572518549918705623086363111",
|
||||
"703671044356805218391078271512201582198770553281951369783674142891088501340774249238173262580562112786670043634665390581120113644316651934154746357220932310140476300088580654571796404198410555061275065442553506658401183560336140989074165998202690496991174269748740565700402715364422506782445179963440819952745241176450402011121226863984008975377353558155910994380700267903933205531681076494639818328879475919332604951949178075254600102192323286738973253864238076198710173840170988339024438220034106150475640983877458155141500313471699516670799821379238743709125064098477109094533426340852518505385314780319279862586851512004686798362431227795743253799490998475141728082088984359237540124375439664236138519644100625154580910233437864328111620708697941949936338367445851449766581651338876219676721272448769082914348242483068204896479076062102236087066428603930888978596966798402915747531679758905013008059396214343112694563043918465373870648649652122703709658068801764236979191262744515840224548957285182453209028157886219424802426566456408109642062498413592155064289314088837031184200671561102160059065729282902863248815224399131391716503171191977463328439766546574118092303414702384104112719959325482439604572518549918705623086363111"
|
||||
);
|
||||
|
||||
export const N_ARRAY = [N_1024, N_1536, N_1792, N_2048, N_3072, N_4096];
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
- 对于数据库中有原创性的内容(如贡献者编辑的描述性内容),如无例外,以 [CC BY 4.0 协议](https://creativecommons.org/licenses/by/4.0/) 提供。
|
||||
- 对于引用、摘编或改编自萌娘百科、VCPedia 的内容,以与原始协议(CC BY-NC-SA 3.0
|
||||
CN)兼容的协议 [CC BY-NC-SA 4.0 协议](https://creativecommons.org/licenses/by-nc-sa/4.0/) 提供,并注明原始协议 。
|
||||
> 根据原始协议第四条第 2 项内容,CC BY-NC-SA 4.0 协议为与原始协议具有相同授权要素的后续版本(“可适用的协议”)。
|
||||
> 根据原始协议第四条第 2 项内容,CC BY-NC-SA 4.0 协议为与原始协议具有相同授权要素的后续版本(“可适用的协议”)。
|
||||
- 中 V 档案馆文档使用 [CC BY 4.0 协议](https://creativecommons.org/licenses/by/4.0/)。
|
||||
|
||||
### 软件代码
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { sql } from "@core/db/dbNew";
|
||||
|
||||
export async function aidExists(aid: number) {
|
||||
const res = await sql`
|
||||
const res = await sql`
|
||||
SELECT 1 FROM bilibili_metadata WHERE aid = ${aid}
|
||||
`;
|
||||
return res.length > 0;
|
||||
}
|
||||
return res.length > 0;
|
||||
}
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import { sql } from "@core/db/dbNew";
|
||||
|
||||
export async function getAidFromBV(bv: string) {
|
||||
const res = await sql`
|
||||
const res = await sql`
|
||||
SELECT aid FROM bilibili_metadata WHERE bvid = ${bv}
|
||||
`
|
||||
if (res.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
const row = res[0];
|
||||
if (row && row.aid) {
|
||||
return Number(row.aid);
|
||||
}
|
||||
return null;
|
||||
`;
|
||||
if (res.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
const row = res[0];
|
||||
if (row && row.aid) {
|
||||
return Number(row.aid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import { sql } from "@core/db/dbNew";
|
||||
|
||||
export async function getVideoMetadata(aid: number) {
|
||||
const res = await sql`
|
||||
const res = await sql`
|
||||
SELECT * FROM bilibili_metadata WHERE aid = ${aid}
|
||||
`;
|
||||
if (res.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
const row = res[0];
|
||||
if (row) {
|
||||
return row;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
if (res.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
const row = res[0];
|
||||
if (row) {
|
||||
return row;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { sql } from "@core/db/dbNew";
|
||||
|
||||
export async function getAllSnapshots(aid: number) {
|
||||
const res = await sql`
|
||||
const res = await sql`
|
||||
SELECT * FROM video_snapshot WHERE aid = ${aid} ORDER BY created_at DESC
|
||||
`;
|
||||
if (res.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
return res;
|
||||
if (res.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
// Define interfaces for input and output
|
||||
interface VdfProgressCallback {
|
||||
(progress: number): void;
|
||||
@ -73,7 +72,12 @@ const workerContent = `addEventListener("message", async (event) => {
|
||||
* @param onProgress - Optional callback function to receive progress updates (0-100).
|
||||
* @returns A Promise that resolves with the VDF result and time taken.
|
||||
*/
|
||||
export function computeVdfInWorker(g: bigint, N: bigint, difficulty: bigint, onProgress?: VdfProgressCallback): Promise<VdfResult> {
|
||||
export function computeVdfInWorker(
|
||||
g: bigint,
|
||||
N: bigint,
|
||||
difficulty: bigint,
|
||||
onProgress?: VdfProgressCallback
|
||||
): Promise<VdfResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Create a Blob containing the worker script
|
||||
const blob = new Blob([workerContent], { type: "text/javascript" });
|
||||
|
||||
@ -1,450 +1,449 @@
|
||||
@font-face {
|
||||
font-family: InterVariable;
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("InterVariable.woff2") format("woff2");
|
||||
font-family: InterVariable;
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("InterVariable.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: InterVariable;
|
||||
font-style: italic;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("InterVariable-Italic.woff2") format("woff2");
|
||||
font-family: InterVariable;
|
||||
font-style: italic;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("InterVariable-Italic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* static fonts */
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-Thin.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-Thin.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-ThinItalic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-ThinItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLight.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLight.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLightItalic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLightItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-Light.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-Light.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-LightItalic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-LightItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Regular.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Italic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Italic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-Medium.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-Medium.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-MediumItalic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-MediumItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBold.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBoldItalic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-Bold.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-Bold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-BoldItalic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-BoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBold.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBoldItalic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-Black.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-Black.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-BlackItalic.woff2") format("woff2");
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-BlackItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Thin.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Thin.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ThinItalic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ThinItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ExtraLight.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ExtraLight.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ExtraLightItalic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ExtraLightItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Light.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Light.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-LightItalic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-LightItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Regular.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Italic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Italic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Medium.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Medium.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-MediumItalic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-MediumItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-SemiBold.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-SemiBold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-SemiBoldItalic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-SemiBoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Bold.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Bold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-BoldItalic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-BoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ExtraBold.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ExtraBold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ExtraBoldItalic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-ExtraBoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Black.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-Black.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-BlackItalic.woff2") format("woff2");
|
||||
font-family: "InterDisplay";
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("InterDisplay-BlackItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-feature-values InterVariable {
|
||||
@character-variant {
|
||||
cv01: 1;
|
||||
cv02: 2;
|
||||
cv03: 3;
|
||||
cv04: 4;
|
||||
cv05: 5;
|
||||
cv06: 6;
|
||||
cv07: 7;
|
||||
cv08: 8;
|
||||
cv09: 9;
|
||||
cv10: 10;
|
||||
cv11: 11;
|
||||
cv12: 12;
|
||||
cv13: 13;
|
||||
alt-1: 1; /* Alternate one */
|
||||
alt-3: 9; /* Flat-top three */
|
||||
open-4: 2; /* Open four */
|
||||
open-6: 3; /* Open six */
|
||||
open-9: 4; /* Open nine */
|
||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||
simplified-u: 6; /* Simplified u */
|
||||
alt-double-s: 7; /* Alternate German double s */
|
||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||
uc-g-with-spur: 10; /* Capital G with spur */
|
||||
single-story-a: 11; /* Single-story a */
|
||||
compact-lc-f: 12; /* Compact f */
|
||||
compact-lc-t: 13; /* Compact t */
|
||||
}
|
||||
@styleset {
|
||||
ss01: 1;
|
||||
ss02: 2;
|
||||
ss03: 3;
|
||||
ss04: 4;
|
||||
ss05: 5;
|
||||
ss06: 6;
|
||||
ss07: 7;
|
||||
ss08: 8;
|
||||
open-digits: 1; /* Open digits */
|
||||
disambiguation: 2; /* Disambiguation (with zero) */
|
||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||
square-punctuation: 7; /* Square punctuation */
|
||||
square-quotes: 8; /* Square quotes */
|
||||
circled-characters: 5; /* Circled characters */
|
||||
squared-characters: 6; /* Squared characters */
|
||||
}
|
||||
@character-variant {
|
||||
cv01: 1;
|
||||
cv02: 2;
|
||||
cv03: 3;
|
||||
cv04: 4;
|
||||
cv05: 5;
|
||||
cv06: 6;
|
||||
cv07: 7;
|
||||
cv08: 8;
|
||||
cv09: 9;
|
||||
cv10: 10;
|
||||
cv11: 11;
|
||||
cv12: 12;
|
||||
cv13: 13;
|
||||
alt-1: 1; /* Alternate one */
|
||||
alt-3: 9; /* Flat-top three */
|
||||
open-4: 2; /* Open four */
|
||||
open-6: 3; /* Open six */
|
||||
open-9: 4; /* Open nine */
|
||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||
simplified-u: 6; /* Simplified u */
|
||||
alt-double-s: 7; /* Alternate German double s */
|
||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||
uc-g-with-spur: 10; /* Capital G with spur */
|
||||
single-story-a: 11; /* Single-story a */
|
||||
compact-lc-f: 12; /* Compact f */
|
||||
compact-lc-t: 13; /* Compact t */
|
||||
}
|
||||
@styleset {
|
||||
ss01: 1;
|
||||
ss02: 2;
|
||||
ss03: 3;
|
||||
ss04: 4;
|
||||
ss05: 5;
|
||||
ss06: 6;
|
||||
ss07: 7;
|
||||
ss08: 8;
|
||||
open-digits: 1; /* Open digits */
|
||||
disambiguation: 2; /* Disambiguation (with zero) */
|
||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||
square-punctuation: 7; /* Square punctuation */
|
||||
square-quotes: 8; /* Square quotes */
|
||||
circled-characters: 5; /* Circled characters */
|
||||
squared-characters: 6; /* Squared characters */
|
||||
}
|
||||
}
|
||||
@font-feature-values Inter {
|
||||
|
||||
@character-variant {
|
||||
cv01: 1;
|
||||
cv02: 2;
|
||||
cv03: 3;
|
||||
cv04: 4;
|
||||
cv05: 5;
|
||||
cv06: 6;
|
||||
cv07: 7;
|
||||
cv08: 8;
|
||||
cv09: 9;
|
||||
cv10: 10;
|
||||
cv11: 11;
|
||||
cv12: 12;
|
||||
cv13: 13;
|
||||
alt-1: 1; /* Alternate one */
|
||||
alt-3: 9; /* Flat-top three */
|
||||
open-4: 2; /* Open four */
|
||||
open-6: 3; /* Open six */
|
||||
open-9: 4; /* Open nine */
|
||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||
simplified-u: 6; /* Simplified u */
|
||||
alt-double-s: 7; /* Alternate German double s */
|
||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||
uc-g-with-spur: 10; /* Capital G with spur */
|
||||
single-story-a: 11; /* Single-story a */
|
||||
compact-lc-f: 12; /* Compact f */
|
||||
compact-lc-t: 13; /* Compact t */
|
||||
}
|
||||
@styleset {
|
||||
ss01: 1;
|
||||
ss02: 2;
|
||||
ss03: 3;
|
||||
ss04: 4;
|
||||
ss05: 5;
|
||||
ss06: 6;
|
||||
ss07: 7;
|
||||
ss08: 8;
|
||||
open-digits: 1; /* Open digits */
|
||||
disambiguation: 2; /* Disambiguation (with zero) */
|
||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||
square-punctuation: 7; /* Square punctuation */
|
||||
square-quotes: 8; /* Square quotes */
|
||||
circled-characters: 5; /* Circled characters */
|
||||
squared-characters: 6; /* Squared characters */
|
||||
}
|
||||
@character-variant {
|
||||
cv01: 1;
|
||||
cv02: 2;
|
||||
cv03: 3;
|
||||
cv04: 4;
|
||||
cv05: 5;
|
||||
cv06: 6;
|
||||
cv07: 7;
|
||||
cv08: 8;
|
||||
cv09: 9;
|
||||
cv10: 10;
|
||||
cv11: 11;
|
||||
cv12: 12;
|
||||
cv13: 13;
|
||||
alt-1: 1; /* Alternate one */
|
||||
alt-3: 9; /* Flat-top three */
|
||||
open-4: 2; /* Open four */
|
||||
open-6: 3; /* Open six */
|
||||
open-9: 4; /* Open nine */
|
||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||
simplified-u: 6; /* Simplified u */
|
||||
alt-double-s: 7; /* Alternate German double s */
|
||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||
uc-g-with-spur: 10; /* Capital G with spur */
|
||||
single-story-a: 11; /* Single-story a */
|
||||
compact-lc-f: 12; /* Compact f */
|
||||
compact-lc-t: 13; /* Compact t */
|
||||
}
|
||||
@styleset {
|
||||
ss01: 1;
|
||||
ss02: 2;
|
||||
ss03: 3;
|
||||
ss04: 4;
|
||||
ss05: 5;
|
||||
ss06: 6;
|
||||
ss07: 7;
|
||||
ss08: 8;
|
||||
open-digits: 1; /* Open digits */
|
||||
disambiguation: 2; /* Disambiguation (with zero) */
|
||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||
square-punctuation: 7; /* Square punctuation */
|
||||
square-quotes: 8; /* Square quotes */
|
||||
circled-characters: 5; /* Circled characters */
|
||||
squared-characters: 6; /* Squared characters */
|
||||
}
|
||||
}
|
||||
@font-feature-values InterDisplay {
|
||||
@character-variant {
|
||||
cv01: 1;
|
||||
cv02: 2;
|
||||
cv03: 3;
|
||||
cv04: 4;
|
||||
cv05: 5;
|
||||
cv06: 6;
|
||||
cv07: 7;
|
||||
cv08: 8;
|
||||
cv09: 9;
|
||||
cv10: 10;
|
||||
cv11: 11;
|
||||
cv12: 12;
|
||||
cv13: 13;
|
||||
alt-1: 1; /* Alternate one */
|
||||
alt-3: 9; /* Flat-top three */
|
||||
open-4: 2; /* Open four */
|
||||
open-6: 3; /* Open six */
|
||||
open-9: 4; /* Open nine */
|
||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||
simplified-u: 6; /* Simplified u */
|
||||
alt-double-s: 7; /* Alternate German double s */
|
||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||
uc-g-with-spur: 10; /* Capital G with spur */
|
||||
single-story-a: 11; /* Single-story a */
|
||||
compact-lc-f: 12; /* Compact f */
|
||||
compact-lc-t: 13; /* Compact t */
|
||||
}
|
||||
@styleset {
|
||||
ss01: 1;
|
||||
ss02: 2;
|
||||
ss03: 3;
|
||||
ss04: 4;
|
||||
ss05: 5;
|
||||
ss06: 6;
|
||||
ss07: 7;
|
||||
ss08: 8;
|
||||
open-digits: 1; /* Open digits */
|
||||
disambiguation: 2; /* Disambiguation (with zero) */
|
||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||
square-punctuation: 7; /* Square punctuation */
|
||||
square-quotes: 8; /* Square quotes */
|
||||
circled-characters: 5; /* Circled characters */
|
||||
squared-characters: 6; /* Squared characters */
|
||||
}
|
||||
@character-variant {
|
||||
cv01: 1;
|
||||
cv02: 2;
|
||||
cv03: 3;
|
||||
cv04: 4;
|
||||
cv05: 5;
|
||||
cv06: 6;
|
||||
cv07: 7;
|
||||
cv08: 8;
|
||||
cv09: 9;
|
||||
cv10: 10;
|
||||
cv11: 11;
|
||||
cv12: 12;
|
||||
cv13: 13;
|
||||
alt-1: 1; /* Alternate one */
|
||||
alt-3: 9; /* Flat-top three */
|
||||
open-4: 2; /* Open four */
|
||||
open-6: 3; /* Open six */
|
||||
open-9: 4; /* Open nine */
|
||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||
simplified-u: 6; /* Simplified u */
|
||||
alt-double-s: 7; /* Alternate German double s */
|
||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||
uc-g-with-spur: 10; /* Capital G with spur */
|
||||
single-story-a: 11; /* Single-story a */
|
||||
compact-lc-f: 12; /* Compact f */
|
||||
compact-lc-t: 13; /* Compact t */
|
||||
}
|
||||
@styleset {
|
||||
ss01: 1;
|
||||
ss02: 2;
|
||||
ss03: 3;
|
||||
ss04: 4;
|
||||
ss05: 5;
|
||||
ss06: 6;
|
||||
ss07: 7;
|
||||
ss08: 8;
|
||||
open-digits: 1; /* Open digits */
|
||||
disambiguation: 2; /* Disambiguation (with zero) */
|
||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||
square-punctuation: 7; /* Square punctuation */
|
||||
square-quotes: 8; /* Square quotes */
|
||||
circled-characters: 5; /* Circled characters */
|
||||
squared-characters: 6; /* Squared characters */
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,88 +1,87 @@
|
||||
@font-face {
|
||||
font-family: "MiSans VF";
|
||||
font-style: normal;
|
||||
font-weight: 150 700;
|
||||
font-display: swap;
|
||||
src: url("MiSans VF.woff2") format("woff2");
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Thin.woff2") format("woff2");
|
||||
font-family: "MiSans VF";
|
||||
font-style: normal;
|
||||
font-weight: 150 700;
|
||||
font-display: swap;
|
||||
src: url("MiSans VF.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("MiSans-ExtraLight.woff2") format("woff2");
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Thin.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Light.woff2") format("woff2");
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("MiSans-ExtraLight.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 360;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Normal.woff2") format("woff2");
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Light.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Regular.woff2") format("woff2");
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 360;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Normal.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Medium.woff2") format("woff2");
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Demibold.woff2") format("woff2");
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Medium.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Semibold.woff2") format("woff2");
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Demibold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Bold.woff2") format("woff2");
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Semibold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Heavy.woff2") format("woff2");
|
||||
}
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Bold.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MiSans";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("MiSans-Heavy.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
.content {
|
||||
|
||||
h1 {
|
||||
@apply text-3xl;
|
||||
}
|
||||
|
||||
@ -1,126 +1,125 @@
|
||||
@import url('InterFont/Inter.css');
|
||||
@import url('MiSans/MiSans.css');
|
||||
@import url("InterFont/Inter.css");
|
||||
@import url("MiSans/MiSans.css");
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
--color-surface-container-high: #f7e4e1;
|
||||
--color-on-surface-variant: #534341;
|
||||
--color-dark-on-surface-variant: #d8c2be;
|
||||
--color-dark-surface-container-high: #322826;
|
||||
--color-dark-surface-container: #271d1c;
|
||||
--color-surface-container: #fceae7;
|
||||
--color-on-surface: #231918;
|
||||
--color-dark-on-surface: #f1dfdc;
|
||||
--color-surface: #fff8f6;
|
||||
--color-dark-surface: #1a1110;
|
||||
--color-primary: #904b40;
|
||||
--color-dark-primary: #ffb2b7;
|
||||
--color-primary-container: #ffdad4;
|
||||
--color-dark-primary-container: #73342a;
|
||||
--color-on-primary: #ffffff;
|
||||
--color-dark-on-primary: #561e16;
|
||||
--color-dark-primary-fixed-dim: #ffb4a8;
|
||||
--color-secondary-container: #ffdad4;
|
||||
--color-dark-secondary-container: #5d3f3b;
|
||||
--color-surface-container-high: #f7e4e1;
|
||||
--color-on-surface-variant: #534341;
|
||||
--color-dark-on-surface-variant: #d8c2be;
|
||||
--color-dark-surface-container-high: #322826;
|
||||
--color-dark-surface-container: #271d1c;
|
||||
--color-surface-container: #fceae7;
|
||||
--color-on-surface: #231918;
|
||||
--color-dark-on-surface: #f1dfdc;
|
||||
--color-surface: #fff8f6;
|
||||
--color-dark-surface: #1a1110;
|
||||
--color-primary: #904b40;
|
||||
--color-dark-primary: #ffb2b7;
|
||||
--color-primary-container: #ffdad4;
|
||||
--color-dark-primary-container: #73342a;
|
||||
--color-on-primary: #ffffff;
|
||||
--color-dark-on-primary: #561e16;
|
||||
--color-dark-primary-fixed-dim: #ffb4a8;
|
||||
--color-secondary-container: #ffdad4;
|
||||
--color-dark-secondary-container: #5d3f3b;
|
||||
|
||||
--color-surface-tint: rgb(144 75 64);
|
||||
--color-dark-surface-tint: rgb(255 180 168);
|
||||
--color-on-primary-container: rgb(115 52 42);
|
||||
--color-dark-on-primary-container: rgb(255 218 212);
|
||||
--color-secondary: rgb(119 86 81);
|
||||
--color-dark-secondary: rgb(231 189 182);
|
||||
--color-on-secondary: rgb(255 255 255);
|
||||
--color-dark-on-secondary: rgb(68 41 37);
|
||||
--color-on-secondary-container: rgb(93 63 59);
|
||||
--color-dark-on-secondary-container: rgb(255 218 212);
|
||||
--color-tertiary: rgb(112 92 46);
|
||||
--color-dark-tertiary: rgb(222 196 140);
|
||||
--color-on-tertiary: rgb(255 255 255);
|
||||
--color-dark-on-tertiary: rgb(62 46 4);
|
||||
--color-tertiary-container: rgb(251 223 166);
|
||||
--color-dark-tertiary-container: rgb(86 68 25);
|
||||
--color-on-tertiary-container: rgb(86 68 25);
|
||||
--color-dark-on-tertiary-container: rgb(251 223 166);
|
||||
--color-error: rgb(186 26 26);
|
||||
--color-dark-error: rgb(255 180 171);
|
||||
--color-on-error: rgb(255 255 255);
|
||||
--color-dark-on-error: rgb(105 0 5);
|
||||
--color-error-container: rgb(255 218 214);
|
||||
--color-dark-error-container: rgb(147 0 10);
|
||||
--color-on-error-container: rgb(147 0 10);
|
||||
--color-dark-on-error-container: rgb(255 218 214);
|
||||
--color-background: rgb(255 248 246);
|
||||
--color-dark-background: rgb(26 17 16);
|
||||
--color-on-background: rgb(35 25 24);
|
||||
--color-dark-on-background: rgb(241 223 220);
|
||||
--color-surface-variant: rgb(245 221 218);
|
||||
--color-dark-surface-variant: rgb(83 67 65);
|
||||
--color-outline: rgb(133 115 112);
|
||||
--color-dark-outline: rgb(160 140 137);
|
||||
--color-outline-variant: rgb(216 194 190);
|
||||
--color-dark-outline-variant: rgb(83 67 65);
|
||||
--color-shadow: rgb(0 0 0);
|
||||
--color-dark-shadow: rgb(0 0 0);
|
||||
--color-scrim: rgb(0 0 0);
|
||||
--color-dark-scrim: rgb(0 0 0);
|
||||
--color-inverse-surface: rgb(57 46 44);
|
||||
--color-dark-inverse-surface: rgb(241 223 220);
|
||||
--color-inverse-on-surface: rgb(255 237 234);
|
||||
--color-dark-inverse-on-surface: rgb(57 46 44);
|
||||
--color-inverse-primary: rgb(255 180 168);
|
||||
--color-dark-inverse-primary: rgb(144 75 64);
|
||||
--color-primary-fixed: rgb(255 218 212);
|
||||
--color-dark-primary-fixed: rgb(255 218 212);
|
||||
--color-on-primary-fixed: rgb(58 9 5);
|
||||
--color-dark-on-primary-fixed: rgb(58 9 5);
|
||||
--color-primary-fixed-dim: rgb(255 180 168);
|
||||
--color-on-primary-fixed-variant: rgb(115 52 42);
|
||||
--color-dark-on-primary-fixed-variant: rgb(115 52 42);
|
||||
--color-secondary-fixed: rgb(255 218 212);
|
||||
--color-dark-secondary-fixed: rgb(255 218 212);
|
||||
--color-on-secondary-fixed: rgb(44 21 18);
|
||||
--color-dark-on-secondary-fixed: rgb(44 21 18);
|
||||
--color-secondary-fixed-dim: rgb(231 189 182);
|
||||
--color-dark-secondary-fixed-dim: rgb(231 189 182);
|
||||
--color-on-secondary-fixed-variant: rgb(93 63 59);
|
||||
--color-dark-on-secondary-fixed-variant: rgb(93 63 59);
|
||||
--color-tertiary-fixed: rgb(251 223 166);
|
||||
--color-dark-tertiary-fixed: rgb(251 223 166);
|
||||
--color-on-tertiary-fixed: rgb(37 26 0);
|
||||
--color-dark-on-tertiary-fixed: rgb(37 26 0);
|
||||
--color-tertiary-fixed-dim: rgb(222 196 140);
|
||||
--color-dark-tertiary-fixed-dim: rgb(222 196 140);
|
||||
--color-on-tertiary-fixed-variant: rgb(86 68 25);
|
||||
--color-dark-on-tertiary-fixed-variant: rgb(86 68 25);
|
||||
--color-surface-dim: rgb(232 214 211);
|
||||
--color-dark-surface-dim: rgb(26 17 16);
|
||||
--color-surface-bright: rgb(255 248 246);
|
||||
--color-dark-surface-bright: rgb(66 55 53);
|
||||
--color-surface-container-lowest: rgb(255 255 255);
|
||||
--color-dark-surface-container-lowest: rgb(20 12 11);
|
||||
--color-surface-container-low: rgb(255 240 238);
|
||||
--color-dark-surface-container-low: rgb(35 25 24);
|
||||
--color-surface-container-highest: rgb(241 223 220);
|
||||
--color-dark-surface-container-highest: rgb(61 50 48);
|
||||
--color-surface-tint: rgb(144 75 64);
|
||||
--color-dark-surface-tint: rgb(255 180 168);
|
||||
--color-on-primary-container: rgb(115 52 42);
|
||||
--color-dark-on-primary-container: rgb(255 218 212);
|
||||
--color-secondary: rgb(119 86 81);
|
||||
--color-dark-secondary: rgb(231 189 182);
|
||||
--color-on-secondary: rgb(255 255 255);
|
||||
--color-dark-on-secondary: rgb(68 41 37);
|
||||
--color-on-secondary-container: rgb(93 63 59);
|
||||
--color-dark-on-secondary-container: rgb(255 218 212);
|
||||
--color-tertiary: rgb(112 92 46);
|
||||
--color-dark-tertiary: rgb(222 196 140);
|
||||
--color-on-tertiary: rgb(255 255 255);
|
||||
--color-dark-on-tertiary: rgb(62 46 4);
|
||||
--color-tertiary-container: rgb(251 223 166);
|
||||
--color-dark-tertiary-container: rgb(86 68 25);
|
||||
--color-on-tertiary-container: rgb(86 68 25);
|
||||
--color-dark-on-tertiary-container: rgb(251 223 166);
|
||||
--color-error: rgb(186 26 26);
|
||||
--color-dark-error: rgb(255 180 171);
|
||||
--color-on-error: rgb(255 255 255);
|
||||
--color-dark-on-error: rgb(105 0 5);
|
||||
--color-error-container: rgb(255 218 214);
|
||||
--color-dark-error-container: rgb(147 0 10);
|
||||
--color-on-error-container: rgb(147 0 10);
|
||||
--color-dark-on-error-container: rgb(255 218 214);
|
||||
--color-background: rgb(255 248 246);
|
||||
--color-dark-background: rgb(26 17 16);
|
||||
--color-on-background: rgb(35 25 24);
|
||||
--color-dark-on-background: rgb(241 223 220);
|
||||
--color-surface-variant: rgb(245 221 218);
|
||||
--color-dark-surface-variant: rgb(83 67 65);
|
||||
--color-outline: rgb(133 115 112);
|
||||
--color-dark-outline: rgb(160 140 137);
|
||||
--color-outline-variant: rgb(216 194 190);
|
||||
--color-dark-outline-variant: rgb(83 67 65);
|
||||
--color-shadow: rgb(0 0 0);
|
||||
--color-dark-shadow: rgb(0 0 0);
|
||||
--color-scrim: rgb(0 0 0);
|
||||
--color-dark-scrim: rgb(0 0 0);
|
||||
--color-inverse-surface: rgb(57 46 44);
|
||||
--color-dark-inverse-surface: rgb(241 223 220);
|
||||
--color-inverse-on-surface: rgb(255 237 234);
|
||||
--color-dark-inverse-on-surface: rgb(57 46 44);
|
||||
--color-inverse-primary: rgb(255 180 168);
|
||||
--color-dark-inverse-primary: rgb(144 75 64);
|
||||
--color-primary-fixed: rgb(255 218 212);
|
||||
--color-dark-primary-fixed: rgb(255 218 212);
|
||||
--color-on-primary-fixed: rgb(58 9 5);
|
||||
--color-dark-on-primary-fixed: rgb(58 9 5);
|
||||
--color-primary-fixed-dim: rgb(255 180 168);
|
||||
--color-on-primary-fixed-variant: rgb(115 52 42);
|
||||
--color-dark-on-primary-fixed-variant: rgb(115 52 42);
|
||||
--color-secondary-fixed: rgb(255 218 212);
|
||||
--color-dark-secondary-fixed: rgb(255 218 212);
|
||||
--color-on-secondary-fixed: rgb(44 21 18);
|
||||
--color-dark-on-secondary-fixed: rgb(44 21 18);
|
||||
--color-secondary-fixed-dim: rgb(231 189 182);
|
||||
--color-dark-secondary-fixed-dim: rgb(231 189 182);
|
||||
--color-on-secondary-fixed-variant: rgb(93 63 59);
|
||||
--color-dark-on-secondary-fixed-variant: rgb(93 63 59);
|
||||
--color-tertiary-fixed: rgb(251 223 166);
|
||||
--color-dark-tertiary-fixed: rgb(251 223 166);
|
||||
--color-on-tertiary-fixed: rgb(37 26 0);
|
||||
--color-dark-on-tertiary-fixed: rgb(37 26 0);
|
||||
--color-tertiary-fixed-dim: rgb(222 196 140);
|
||||
--color-dark-tertiary-fixed-dim: rgb(222 196 140);
|
||||
--color-on-tertiary-fixed-variant: rgb(86 68 25);
|
||||
--color-dark-on-tertiary-fixed-variant: rgb(86 68 25);
|
||||
--color-surface-dim: rgb(232 214 211);
|
||||
--color-dark-surface-dim: rgb(26 17 16);
|
||||
--color-surface-bright: rgb(255 248 246);
|
||||
--color-dark-surface-bright: rgb(66 55 53);
|
||||
--color-surface-container-lowest: rgb(255 255 255);
|
||||
--color-dark-surface-container-lowest: rgb(20 12 11);
|
||||
--color-surface-container-low: rgb(255 240 238);
|
||||
--color-dark-surface-container-low: rgb(35 25 24);
|
||||
--color-surface-container-highest: rgb(241 223 220);
|
||||
--color-dark-surface-container-highest: rgb(61 50 48);
|
||||
|
||||
--font-zh: "InterVariable", "MiSans VF", sans-serif;
|
||||
--font-zh: "InterVariable", "MiSans VF", sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-primary dark:text-dark-primary;
|
||||
@apply text-primary dark:text-dark-primary;
|
||||
}
|
||||
|
||||
|
||||
:root {
|
||||
font-family: "MiSans", "Inter", sans-serif;
|
||||
font-weight: 400;
|
||||
@apply bg-surface dark:bg-dark-surface text-on-surface dark:text-dark-on-surface
|
||||
font-family: "MiSans", "Inter", sans-serif;
|
||||
font-weight: 400;
|
||||
@apply bg-surface dark:bg-dark-surface text-on-surface dark:text-dark-on-surface;
|
||||
}
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
:root {
|
||||
font-family: "InterVariable", "MiSans VF", sans-serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 330;
|
||||
}
|
||||
:root {
|
||||
font-family: "InterVariable", "MiSans VF", sans-serif;
|
||||
font-optical-sizing: auto;
|
||||
font-weight: 330;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
extend: {}
|
||||
},
|
||||
plugins: [],
|
||||
plugins: []
|
||||
};
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
"@lib/*": ["src/lib/*"],
|
||||
"@assets/*": ["src/assets/*"],
|
||||
"@styles": ["src/styles/*"],
|
||||
"@core/*": ["../core/*"],
|
||||
"@core/*": ["../core/*"]
|
||||
},
|
||||
"verbatimModuleSyntax": true
|
||||
}
|
||||
|
||||
@ -65,9 +65,7 @@ const OutlineTextField: React.FC<InputProps> = ({
|
||||
|
||||
<div
|
||||
className={`flex-grow rounded-r-sm border-outline dark:border-dark-outline
|
||||
${focus ?
|
||||
"border-primary dark:border-dark-primary border-r-2 border-y-2" :
|
||||
"border-r-[1px] border-y-[1px] "}
|
||||
${focus ? "border-primary dark:border-dark-primary border-r-2 border-y-2" : "border-r-[1px] border-y-[1px] "}
|
||||
`}
|
||||
></div>
|
||||
</div>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
- 对于数据库中有原创性的内容(如贡献者编辑的描述性内容),如无例外,以 [CC BY 4.0 协议](https://creativecommons.org/licenses/by/4.0/) 提供。
|
||||
- 对于引用、摘编或改编自萌娘百科、VCPedia 的内容,以与原始协议(CC BY-NC-SA 3.0
|
||||
CN)兼容的协议 [CC BY-NC-SA 4.0 协议](https://creativecommons.org/licenses/by-nc-sa/4.0/) 提供,并注明原始协议 。
|
||||
> 根据原始协议第四条第 2 项内容,CC BY-NC-SA 4.0 协议为与原始协议具有相同授权要素的后续版本(“可适用的协议”)。
|
||||
> 根据原始协议第四条第 2 项内容,CC BY-NC-SA 4.0 协议为与原始协议具有相同授权要素的后续版本(“可适用的协议”)。
|
||||
- 中 V 档案馆文档使用 [CC BY 4.0 协议](https://creativecommons.org/licenses/by/4.0/)。
|
||||
|
||||
### 软件代码
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap" rel="stylesheet" />
|
||||
</head>
|
||||
<body class="bg-gray-50 dark:bg-black dark:text-gray-50 ">
|
||||
<body class="bg-gray-50 dark:bg-black dark:text-gray-50">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
@ -22,8 +22,8 @@ export const Switch: React.FC<SwitchProps> = ({ checked, onChange, disabled = fa
|
||||
disabled={disabled}
|
||||
className={`relative flex items-center justify-center w-12 h-6 rounded-full transition-all duration-300
|
||||
focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 ${
|
||||
disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:scale-105"
|
||||
} ${checked ? "bg-green-500" : "bg-zinc-300 dark:bg-zinc-600"}`}
|
||||
disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:scale-105"
|
||||
} ${checked ? "bg-green-500" : "bg-zinc-300 dark:bg-zinc-600"}`}
|
||||
aria-checked={checked}
|
||||
aria-disabled={disabled}
|
||||
>
|
||||
@ -49,4 +49,4 @@ export const Switch: React.FC<SwitchProps> = ({ checked, onChange, disabled = fa
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,7 +2,7 @@ import { SVGProps } from "react";
|
||||
|
||||
export const Checkmark: React.FC<SVGProps<SVGSVGElement>> = (props) => {
|
||||
return (
|
||||
<svg viewBox="10 5 90 85" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<svg viewBox="10 5 90 85" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
@ -27,4 +27,4 @@ export const Checkmark: React.FC<SVGProps<SVGSVGElement>> = (props) => {
|
||||
</style>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@ -6,80 +6,82 @@ import { Checkmark } from "./Check";
|
||||
import { getAdjustedColor } from "../utils";
|
||||
|
||||
interface ColorBlockProps {
|
||||
baseColor: Oklch;
|
||||
text: string;
|
||||
l?: number;
|
||||
c?: number;
|
||||
h?: number;
|
||||
baseColor: Oklch;
|
||||
text: string;
|
||||
l?: number;
|
||||
c?: number;
|
||||
h?: number;
|
||||
}
|
||||
|
||||
const copy = async (text: string) => {
|
||||
await navigator.clipboard.writeText(text);
|
||||
};
|
||||
|
||||
|
||||
export const ColorBlock = ({ baseColor, text, l, c, h }: ColorBlockProps) => {
|
||||
const [hover, setHover] = useState(false);
|
||||
const [check, setCheck] = useState(false);
|
||||
const color = getAdjustedColor(baseColor, l, c, h);
|
||||
const [hover, setHover] = useState(false);
|
||||
const [check, setCheck] = useState(false);
|
||||
const color = getAdjustedColor(baseColor, l, c, h);
|
||||
|
||||
const Icon = () => {
|
||||
if (!check) {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<motion.div exit={{ opacity: 0 }} initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
||||
<Copy size={14} strokeWidth={2.5} />
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<motion.div exit={{ opacity: 0 }} initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
||||
<Checkmark width={16} height={16} strokeWidth={14} />
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
};
|
||||
const Icon = () => {
|
||||
if (!check) {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<motion.div exit={{ opacity: 0 }} initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
||||
<Copy size={14} strokeWidth={2.5} />
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<motion.div exit={{ opacity: 0 }} initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
||||
<Checkmark width={16} height={16} strokeWidth={14} />
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-26 md:w-30 h-36 flex flex-col items-center">
|
||||
<div className="w-full h-20 relative rounded-lg duration-50" style={{ backgroundColor: formatHex(color) }} />
|
||||
<span className="mt-2 text-sm">{text}</span>
|
||||
<div
|
||||
className="flex items-center justify-center text-sm font-medium px-2 py-0.5 cursor-pointer
|
||||
return (
|
||||
<div className="w-26 md:w-30 h-36 flex flex-col items-center">
|
||||
<div
|
||||
className="w-full h-20 relative rounded-lg duration-50"
|
||||
style={{ backgroundColor: formatHex(color) }}
|
||||
/>
|
||||
<span className="mt-2 text-sm">{text}</span>
|
||||
<div
|
||||
className="flex items-center justify-center text-sm font-medium px-2 py-0.5 cursor-pointer
|
||||
mt-1 hover:bg-gray-200 dark:hover:bg-zinc-700 rounded-md"
|
||||
onClick={() => {
|
||||
copy(formatHex(color));
|
||||
setCheck(true);
|
||||
setTimeout(() => {
|
||||
setCheck(false);
|
||||
}, 2500);
|
||||
}}
|
||||
onMouseEnter={() => setHover(true)}
|
||||
onMouseLeave={() => {
|
||||
setHover(false);
|
||||
setCheck(false);
|
||||
}}
|
||||
>
|
||||
<AnimatePresence>
|
||||
{hover && (
|
||||
<motion.div
|
||||
exit={{ opacity: 0, width: 0 }}
|
||||
initial={{ opacity: 0, width: 0 }}
|
||||
animate={{ opacity: 1, width: 22 }}
|
||||
transition={{
|
||||
opacity: { duration: 0.2, ease: "backOut" },
|
||||
width: { type: "spring", bounce: 0.2, duration: 0.5 }
|
||||
}}
|
||||
>
|
||||
<Icon />
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
{formatHex(color)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
onClick={() => {
|
||||
copy(formatHex(color));
|
||||
setCheck(true);
|
||||
setTimeout(() => {
|
||||
setCheck(false);
|
||||
}, 2500);
|
||||
}}
|
||||
onMouseEnter={() => setHover(true)}
|
||||
onMouseLeave={() => {
|
||||
setHover(false);
|
||||
setCheck(false);
|
||||
}}
|
||||
>
|
||||
<AnimatePresence>
|
||||
{hover && (
|
||||
<motion.div
|
||||
exit={{ opacity: 0, width: 0 }}
|
||||
initial={{ opacity: 0, width: 0 }}
|
||||
animate={{ opacity: 1, width: 22 }}
|
||||
transition={{
|
||||
opacity: { duration: 0.2, ease: "backOut" },
|
||||
width: { type: "spring", bounce: 0.2, duration: 0.5 }
|
||||
}}
|
||||
>
|
||||
<Icon />
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
{formatHex(color)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -8,8 +8,10 @@ export function ColorPalette({ baseColor }: { baseColor: Oklch }) {
|
||||
const tokens = buildColorTokens(baseColor)[theme];
|
||||
|
||||
return (
|
||||
<div className="mx-6 grid gap-1 md:gap-4 [grid-template-columns:repeat(auto-fill,104px)]
|
||||
md:[grid-template-columns:repeat(auto-fill,120px)] justify-between">
|
||||
<div
|
||||
className="mx-6 grid gap-1 md:gap-4 [grid-template-columns:repeat(auto-fill,104px)]
|
||||
md:[grid-template-columns:repeat(auto-fill,120px)] justify-between"
|
||||
>
|
||||
{Object.entries(tokens).map(([name, color]) => (
|
||||
<ColorBlock key={name} baseColor={color} text={name} />
|
||||
))}
|
||||
|
||||
@ -26,7 +26,7 @@ export const Handle = ({
|
||||
|
||||
const x = clientX - sliderRect.left;
|
||||
const percentage = Math.max(0, Math.min(1, x / sliderRect.width));
|
||||
return (percentage * maxValue);
|
||||
return percentage * maxValue;
|
||||
};
|
||||
|
||||
const handleMouseDown = () => {
|
||||
@ -50,13 +50,13 @@ export const Handle = ({
|
||||
|
||||
const handleTouchStart = (e: React.TouchEvent) => {
|
||||
isTouching.current = true;
|
||||
|
||||
|
||||
const touch = e.touches[0];
|
||||
if (touch) {
|
||||
const value = getValueFromPosition(touch.clientX);
|
||||
onChange(value);
|
||||
}
|
||||
|
||||
|
||||
onTouchStart?.(e);
|
||||
};
|
||||
|
||||
@ -94,4 +94,4 @@ export const Handle = ({
|
||||
onTouchCancel={handleTouchEnd}
|
||||
/>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@ -23,14 +23,14 @@ export const Slider = ({ useP3, channel, color, onChange, i18nProvider }: Slider
|
||||
|
||||
const canvasRef = useRef<null | HTMLCanvasElement>(null);
|
||||
useOklchCanvas({ channel: channel, max: maxValue[channel], canvasRef: canvasRef, color, useP3 });
|
||||
|
||||
|
||||
const getSliderPosition = (value: number, max: number) => {
|
||||
return (value / max) * 100;
|
||||
};
|
||||
|
||||
const getValueFromPosition = (clientX: number) => {
|
||||
if (!containerRef.current) return 0;
|
||||
|
||||
|
||||
const rect = containerRef.current.getBoundingClientRect();
|
||||
const x = clientX - rect.left;
|
||||
const percentage = Math.max(0, Math.min(1, x / rect.width));
|
||||
@ -122,7 +122,7 @@ export const Slider = ({ useP3, channel, color, onChange, i18nProvider }: Slider
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative h-10"
|
||||
onTouchMove={handleTouchMove}
|
||||
@ -152,4 +152,4 @@ export const Slider = ({ useP3, channel, color, onChange, i18nProvider }: Slider
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,10 +2,10 @@ import { useEffect, type RefObject } from "react";
|
||||
import { oklch, formatHex, inGamut, type Oklch } from "culori";
|
||||
|
||||
interface UseOklchCanvasOptions {
|
||||
useP3: boolean
|
||||
useP3: boolean;
|
||||
channel: "l" | "c" | "h";
|
||||
max: number;
|
||||
canvasRef: RefObject<HTMLCanvasElement | null>
|
||||
canvasRef: RefObject<HTMLCanvasElement | null>;
|
||||
color: Oklch;
|
||||
}
|
||||
|
||||
|
||||
@ -57,11 +57,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: "Martian Mono";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("/MartianMono.woff2") format("woff2");
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,14 +3,13 @@ import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App.tsx";
|
||||
import { ThemeProvider } from "./ThemeContext.tsx";
|
||||
import { SpeedInsights } from "@vercel/speed-insights/react"
|
||||
|
||||
import { SpeedInsights } from "@vercel/speed-insights/react";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<ThemeProvider>
|
||||
<App />
|
||||
<SpeedInsights/>
|
||||
<SpeedInsights />
|
||||
</ThemeProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
@ -16,11 +16,10 @@ export const i18nProvider = (key: i18nKeys) => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const getAdjustedColor = (color: Oklch, l?: number, c?: number, h?: number) => {
|
||||
const newColor = { ...color };
|
||||
if (l) newColor.l = l;
|
||||
if (c) newColor.c = c;
|
||||
if (h) newColor.h = h;
|
||||
return newColor;
|
||||
};
|
||||
const newColor = { ...color };
|
||||
if (l) newColor.l = l;
|
||||
if (c) newColor.c = c;
|
||||
if (h) newColor.h = h;
|
||||
return newColor;
|
||||
};
|
||||
|
||||
@ -2,8 +2,6 @@ import presetWind4 from "@unocss/preset-wind4";
|
||||
import { defineConfig } from "unocss";
|
||||
|
||||
export default defineConfig({
|
||||
presets: [presetWind4({ dark: "media"})],
|
||||
rules: [
|
||||
['font-mono', { 'font-family': '"Martian Mono", monospace' }],
|
||||
]
|
||||
presets: [presetWind4({ dark: "media" })],
|
||||
rules: [["font-mono", { "font-family": '"Martian Mono", monospace' }]]
|
||||
});
|
||||
|
||||
@ -7,5 +7,5 @@ export default defineConfig({
|
||||
dbCredentials: {
|
||||
url: process.env.DATABASE_URL_MAIN!
|
||||
},
|
||||
tablesFilter: ["*"],
|
||||
tablesFilter: ["*"]
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@import url("https://assets.projectcvsa.com/hm-sans/index.css");
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap");
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
|
||||
@ -4,7 +4,7 @@ import { TabSwitcher } from "~/components/song/TabSwitcher";
|
||||
import { Staff } from "~/components/song/Staff";
|
||||
import { SongType } from "~db/outerSchema";
|
||||
|
||||
export const Content: Component<{data: SongType | null}> = (props) => {
|
||||
export const Content: Component<{ data: SongType | null }> = (props) => {
|
||||
return (
|
||||
<>
|
||||
<Card variant="outlined" class="w-full max-lg:rounded-none max-lg:border-none">
|
||||
@ -145,4 +145,4 @@ export const Content: Component<{data: SongType | null}> = (props) => {
|
||||
</article>
|
||||
</>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@ -48,4 +48,4 @@ export const LeftSideBar: Component = () => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@ -14,4 +14,4 @@ export const RightSideBar: Component = () => {
|
||||
<TabSwitcher />
|
||||
</>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@ -34,4 +34,4 @@ export const Staff: Component<{ name: string; role: string; num: number }> = (pr
|
||||
</IconButton>
|
||||
</A>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@ -15,9 +15,7 @@ export default createHandler(() => (
|
||||
{assets}
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
{children}
|
||||
</div>
|
||||
<div id="app">{children}</div>
|
||||
<div id="modal"></div>
|
||||
{scripts}
|
||||
</body>
|
||||
|
||||
@ -12,24 +12,24 @@ const getVideoAID = async (id: string) => {
|
||||
if (id.startsWith("av")) {
|
||||
return parseInt(id.slice(2));
|
||||
} else if (id.startsWith("BV")) {
|
||||
const data = await dbMain
|
||||
.select()
|
||||
.from(bilibiliMetadata)
|
||||
.where(eq(bilibiliMetadata.bvid, id));
|
||||
const data = await dbMain.select().from(bilibiliMetadata).where(eq(bilibiliMetadata.bvid, id));
|
||||
return data[0].aid;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const findSongIDFromAID = async (aid: number) => {
|
||||
"use server";
|
||||
const data = await dbMain.select({
|
||||
id: songs.id,
|
||||
}).from(songs).where(eq(songs.aid, aid)).limit(1);
|
||||
const data = await dbMain
|
||||
.select({
|
||||
id: songs.id
|
||||
})
|
||||
.from(songs)
|
||||
.where(eq(songs.aid, aid))
|
||||
.limit(1);
|
||||
return data[0].id;
|
||||
}
|
||||
};
|
||||
|
||||
const getSongInfo = query(async (songID: number) => {
|
||||
"use server";
|
||||
@ -42,19 +42,17 @@ const getSongInfoFromID = query(async (id: string) => {
|
||||
const aid = await getVideoAID(id);
|
||||
if (!aid && parseInt(id)) {
|
||||
return getSongInfo(parseInt(id));
|
||||
}
|
||||
else if (!aid) {
|
||||
} else if (!aid) {
|
||||
return null;
|
||||
}
|
||||
const songID = await findSongIDFromAID(aid);
|
||||
return getSongInfo(songID);
|
||||
}, "songsRaw")
|
||||
}, "songsRaw");
|
||||
|
||||
export const route = {
|
||||
preload: ({ params }) => getSongInfoFromID(params.id)
|
||||
} satisfies RouteDefinition;
|
||||
|
||||
|
||||
export default function Info() {
|
||||
const params = useParams();
|
||||
const info = createAsync(() => getSongInfoFromID(params.id));
|
||||
@ -69,7 +67,7 @@ export default function Info() {
|
||||
<LeftSideBar />
|
||||
</nav>
|
||||
<main class="mb-24">
|
||||
<Content data={info() || null}/>
|
||||
<Content data={info() || null} />
|
||||
</main>
|
||||
<div class="top-32 hidden lg:flex self-start sticky flex-col pb-12 px-6">
|
||||
<RightSideBar />
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
"isolatedModules": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"],
|
||||
"~db/*": ["../core/drizzle/*"],
|
||||
"~db/*": ["../core/drizzle/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user