mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 02:19:08 +03:00
directus setup
This commit is contained in:
parent
8b26bc8bbc
commit
a9061822f0
@ -1,3 +1,4 @@
|
||||
REDIS_HOST=redis-1234.p124.eu-central-5-5.ec2.cloud.redislabs.com
|
||||
REDIS_PASSWORD=superpassword
|
||||
REDIS_PORT=1234
|
||||
REDIS_PORT=1234
|
||||
DIRECTUS_TOKEN=
|
||||
@ -1,8 +1,9 @@
|
||||
import { defineConfig } from "astro/config";
|
||||
import { defineConfig, envField } from "astro/config";
|
||||
|
||||
/**
|
||||
* Integrations
|
||||
*/
|
||||
import node from "@astrojs/node";
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
import solidJs from "@astrojs/solid-js";
|
||||
import icon from "astro-icon";
|
||||
@ -32,6 +33,15 @@ const createAnchorLabel = (heading) => {
|
||||
export default defineConfig({
|
||||
site: "https://yarkov.tech",
|
||||
compressHTML: true,
|
||||
output: "server",
|
||||
adapter: node({
|
||||
mode: "standalone",
|
||||
}),
|
||||
env: {
|
||||
schema: {
|
||||
DIRECTUS_TOKEN: envField.string({ context: "server", access: "secret", default: "" }),
|
||||
},
|
||||
},
|
||||
integrations: [
|
||||
sitemap({
|
||||
i18n: {
|
||||
|
||||
578
directus-schema.ts
Normal file
578
directus-schema.ts
Normal file
@ -0,0 +1,578 @@
|
||||
export interface Article {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
tags?: ArticleTag[] | string[];
|
||||
/** @required */
|
||||
translations: ArticleTranslation[] | null;
|
||||
}
|
||||
|
||||
export interface ArticleTag {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
article_id?: Article | string | null;
|
||||
tag_id?: Tag | string | null;
|
||||
}
|
||||
|
||||
export interface ArticleTranslation {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
article_id?: Article | string | null;
|
||||
languages_code?: Language | string | null;
|
||||
title?: string | null;
|
||||
description?: string | null;
|
||||
slug?: string | null;
|
||||
content?: string | null;
|
||||
status?: 'published' | 'draft' | 'archived' | null;
|
||||
author?: DirectusUser | string | null;
|
||||
pub_date?: string | null;
|
||||
views?: number | null;
|
||||
}
|
||||
|
||||
export interface Global {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
translations?: GlobalTranslation[] | null;
|
||||
}
|
||||
|
||||
export interface GlobalTranslation {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
global_id?: Global | string | null;
|
||||
languages_code?: Language | string | null;
|
||||
description?: string | null;
|
||||
}
|
||||
|
||||
export interface Language {
|
||||
/** @primaryKey */
|
||||
code: string;
|
||||
name?: string | null;
|
||||
direction?: 'ltr' | 'rtl' | null;
|
||||
}
|
||||
|
||||
export interface Tag {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
/** @required */
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface DirectusAccess {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
role?: DirectusRole | string | null;
|
||||
user?: DirectusUser | string | null;
|
||||
policy?: DirectusPolicy | string;
|
||||
sort?: number | null;
|
||||
}
|
||||
|
||||
export interface DirectusActivity {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
action?: string;
|
||||
user?: DirectusUser | string | null;
|
||||
timestamp?: string;
|
||||
ip?: string | null;
|
||||
user_agent?: string | null;
|
||||
collection?: string;
|
||||
item?: string;
|
||||
origin?: string | null;
|
||||
revisions?: DirectusRevision[] | string[];
|
||||
}
|
||||
|
||||
export interface DirectusCollection {
|
||||
/** @primaryKey */
|
||||
collection: string;
|
||||
icon?: string | null;
|
||||
note?: string | null;
|
||||
display_template?: string | null;
|
||||
hidden?: boolean;
|
||||
singleton?: boolean;
|
||||
translations?: Array<{ language: string; translation: string; singular: string; plural: string }> | null;
|
||||
archive_field?: string | null;
|
||||
archive_app_filter?: boolean;
|
||||
archive_value?: string | null;
|
||||
unarchive_value?: string | null;
|
||||
sort_field?: string | null;
|
||||
accountability?: 'all' | 'activity' | null | null;
|
||||
color?: string | null;
|
||||
item_duplication_fields?: 'json' | null;
|
||||
sort?: number | null;
|
||||
group?: DirectusCollection | string | null;
|
||||
collapse?: string;
|
||||
preview_url?: string | null;
|
||||
versioning?: boolean;
|
||||
}
|
||||
|
||||
export interface DirectusComment {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
collection?: DirectusCollection | string;
|
||||
item?: string;
|
||||
comment?: string;
|
||||
date_created?: string | null;
|
||||
date_updated?: string | null;
|
||||
user_created?: DirectusUser | string | null;
|
||||
user_updated?: DirectusUser | string | null;
|
||||
}
|
||||
|
||||
export interface DirectusField {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
collection?: DirectusCollection | string;
|
||||
field?: string;
|
||||
special?: string[] | null;
|
||||
interface?: string | null;
|
||||
options?: 'json' | null;
|
||||
display?: string | null;
|
||||
display_options?: 'json' | null;
|
||||
readonly?: boolean;
|
||||
hidden?: boolean;
|
||||
sort?: number | null;
|
||||
width?: string | null;
|
||||
translations?: 'json' | null;
|
||||
note?: string | null;
|
||||
conditions?: 'json' | null;
|
||||
required?: boolean | null;
|
||||
group?: DirectusField | string | null;
|
||||
validation?: 'json' | null;
|
||||
validation_message?: string | null;
|
||||
searchable?: boolean;
|
||||
}
|
||||
|
||||
export interface DirectusFile {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
storage?: string;
|
||||
filename_disk?: string | null;
|
||||
filename_download?: string;
|
||||
title?: string | null;
|
||||
type?: string | null;
|
||||
folder?: DirectusFolder | string | null;
|
||||
uploaded_by?: DirectusUser | string | null;
|
||||
created_on?: string;
|
||||
modified_by?: DirectusUser | string | null;
|
||||
modified_on?: string;
|
||||
charset?: string | null;
|
||||
filesize?: number | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
duration?: number | null;
|
||||
embed?: string | null;
|
||||
description?: string | null;
|
||||
location?: string | null;
|
||||
tags?: string[] | null;
|
||||
metadata?: 'json' | null;
|
||||
focal_point_x?: number | null;
|
||||
focal_point_y?: number | null;
|
||||
tus_id?: string | null;
|
||||
tus_data?: 'json' | null;
|
||||
uploaded_on?: string | null;
|
||||
}
|
||||
|
||||
export interface DirectusFolder {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
name?: string;
|
||||
parent?: DirectusFolder | string | null;
|
||||
}
|
||||
|
||||
export interface DirectusMigration {
|
||||
/** @primaryKey */
|
||||
version: string;
|
||||
name?: string;
|
||||
timestamp?: string | null;
|
||||
}
|
||||
|
||||
export interface DirectusPermission {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
collection?: string;
|
||||
action?: string;
|
||||
permissions?: 'json' | null;
|
||||
validation?: 'json' | null;
|
||||
presets?: 'json' | null;
|
||||
fields?: string[] | null;
|
||||
policy?: DirectusPolicy | string;
|
||||
}
|
||||
|
||||
export interface DirectusPolicy {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
/** @required */
|
||||
name: string;
|
||||
icon?: string;
|
||||
description?: string | null;
|
||||
ip_access?: string[] | null;
|
||||
enforce_tfa?: boolean;
|
||||
admin_access?: boolean;
|
||||
app_access?: boolean;
|
||||
permissions?: DirectusPermission[] | string[];
|
||||
users?: DirectusAccess[] | string[];
|
||||
roles?: DirectusAccess[] | string[];
|
||||
}
|
||||
|
||||
export interface DirectusPreset {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
bookmark?: string | null;
|
||||
user?: DirectusUser | string | null;
|
||||
role?: DirectusRole | string | null;
|
||||
collection?: string | null;
|
||||
search?: string | null;
|
||||
layout?: string | null;
|
||||
layout_query?: 'json' | null;
|
||||
layout_options?: 'json' | null;
|
||||
refresh_interval?: number | null;
|
||||
filter?: 'json' | null;
|
||||
icon?: string | null;
|
||||
color?: string | null;
|
||||
}
|
||||
|
||||
export interface DirectusRelation {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
many_collection?: string;
|
||||
many_field?: string;
|
||||
one_collection?: string | null;
|
||||
one_field?: string | null;
|
||||
one_collection_field?: string | null;
|
||||
one_allowed_collections?: string[] | null;
|
||||
junction_field?: string | null;
|
||||
sort_field?: string | null;
|
||||
one_deselect_action?: string;
|
||||
}
|
||||
|
||||
export interface DirectusRevision {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
activity?: DirectusActivity | string;
|
||||
collection?: string;
|
||||
item?: string;
|
||||
data?: 'json' | null;
|
||||
delta?: 'json' | null;
|
||||
parent?: DirectusRevision | string | null;
|
||||
version?: DirectusVersion | string | null;
|
||||
}
|
||||
|
||||
export interface DirectusRole {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
/** @required */
|
||||
name: string;
|
||||
icon?: string;
|
||||
description?: string | null;
|
||||
parent?: DirectusRole | string | null;
|
||||
children?: DirectusRole[] | string[];
|
||||
policies?: DirectusAccess[] | string[];
|
||||
users?: DirectusUser[] | string[];
|
||||
}
|
||||
|
||||
export interface DirectusSession {
|
||||
/** @primaryKey */
|
||||
token: string;
|
||||
user?: DirectusUser | string | null;
|
||||
expires?: string;
|
||||
ip?: string | null;
|
||||
user_agent?: string | null;
|
||||
share?: DirectusShare | string | null;
|
||||
origin?: string | null;
|
||||
next_token?: string | null;
|
||||
}
|
||||
|
||||
export interface DirectusSettings {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
project_name?: string;
|
||||
project_url?: string | null;
|
||||
project_color?: string;
|
||||
project_logo?: DirectusFile | string | null;
|
||||
public_foreground?: DirectusFile | string | null;
|
||||
public_background?: DirectusFile | string | null;
|
||||
public_note?: string | null;
|
||||
auth_login_attempts?: number | null;
|
||||
auth_password_policy?: null | `/^.{8,}$/` | `/(?=^.{8,}$)(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{';'?>.<,])(?!.*\\s).*$/` | null;
|
||||
storage_asset_transform?: 'all' | 'none' | 'presets' | null;
|
||||
storage_asset_presets?: Array<{ key: string; fit: 'contain' | 'cover' | 'inside' | 'outside'; width: number; height: number; quality: number; withoutEnlargement: boolean; format: 'auto' | 'jpeg' | 'png' | 'webp' | 'tiff' | 'avif'; transforms: 'json' }> | null;
|
||||
custom_css?: string | null;
|
||||
storage_default_folder?: DirectusFolder | string | null;
|
||||
basemaps?: Array<{ name: string; type: 'raster' | 'tile' | 'style'; url: string; tileSize: number; attribution: string }> | null;
|
||||
mapbox_key?: string | null;
|
||||
module_bar?: 'json' | null;
|
||||
project_descriptor?: string | null;
|
||||
default_language?: string;
|
||||
custom_aspect_ratios?: Array<{ text: string; value: number }> | null;
|
||||
public_favicon?: DirectusFile | string | null;
|
||||
default_appearance?: 'auto' | 'light' | 'dark';
|
||||
default_theme_light?: string | null;
|
||||
theme_light_overrides?: 'json' | null;
|
||||
default_theme_dark?: string | null;
|
||||
theme_dark_overrides?: 'json' | null;
|
||||
report_error_url?: string | null;
|
||||
report_bug_url?: string | null;
|
||||
report_feature_url?: string | null;
|
||||
public_registration?: boolean;
|
||||
public_registration_verify_email?: boolean;
|
||||
public_registration_role?: DirectusRole | string | null;
|
||||
public_registration_email_filter?: 'json' | null;
|
||||
visual_editor_urls?: Array<{ url: string }> | null;
|
||||
project_id?: string | null;
|
||||
mcp_enabled?: boolean;
|
||||
mcp_allow_deletes?: boolean;
|
||||
mcp_prompts_collection?: string | null;
|
||||
mcp_system_prompt_enabled?: boolean;
|
||||
mcp_system_prompt?: string | null;
|
||||
project_owner?: string | null;
|
||||
project_usage?: string | null;
|
||||
org_name?: string | null;
|
||||
product_updates?: boolean | null;
|
||||
project_status?: string | null;
|
||||
}
|
||||
|
||||
export interface DirectusUser {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
first_name?: string | null;
|
||||
last_name?: string | null;
|
||||
email?: string | null;
|
||||
password?: string | null;
|
||||
location?: string | null;
|
||||
title?: string | null;
|
||||
description?: string | null;
|
||||
tags?: string[] | null;
|
||||
avatar?: DirectusFile | string | null;
|
||||
language?: string | null;
|
||||
tfa_secret?: string | null;
|
||||
status?: 'draft' | 'invited' | 'unverified' | 'active' | 'suspended' | 'archived';
|
||||
role?: DirectusRole | string | null;
|
||||
token?: string | null;
|
||||
last_access?: string | null;
|
||||
last_page?: string | null;
|
||||
provider?: string;
|
||||
external_identifier?: string | null;
|
||||
auth_data?: 'json' | null;
|
||||
email_notifications?: boolean | null;
|
||||
appearance?: null | 'auto' | 'light' | 'dark' | null;
|
||||
theme_dark?: string | null;
|
||||
theme_light?: string | null;
|
||||
theme_light_overrides?: 'json' | null;
|
||||
theme_dark_overrides?: 'json' | null;
|
||||
text_direction?: 'auto' | 'ltr' | 'rtl';
|
||||
policies?: DirectusAccess[] | string[];
|
||||
}
|
||||
|
||||
export interface DirectusWebhook {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
name?: string;
|
||||
method?: null;
|
||||
url?: string;
|
||||
status?: 'active' | 'inactive';
|
||||
data?: boolean;
|
||||
actions?: 'create' | 'update' | 'delete';
|
||||
collections?: string[];
|
||||
headers?: Array<{ header: string; value: string }> | null;
|
||||
was_active_before_deprecation?: boolean;
|
||||
migrated_flow?: DirectusFlow | string | null;
|
||||
}
|
||||
|
||||
export interface DirectusDashboard {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
name?: string;
|
||||
icon?: string;
|
||||
note?: string | null;
|
||||
date_created?: string | null;
|
||||
user_created?: DirectusUser | string | null;
|
||||
color?: string | null;
|
||||
panels?: DirectusPanel[] | string[];
|
||||
}
|
||||
|
||||
export interface DirectusPanel {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
dashboard?: DirectusDashboard | string;
|
||||
name?: string | null;
|
||||
icon?: string | null;
|
||||
color?: string | null;
|
||||
show_header?: boolean;
|
||||
note?: string | null;
|
||||
type?: string;
|
||||
position_x?: number;
|
||||
position_y?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
options?: 'json' | null;
|
||||
date_created?: string | null;
|
||||
user_created?: DirectusUser | string | null;
|
||||
}
|
||||
|
||||
export interface DirectusNotification {
|
||||
/** @primaryKey */
|
||||
id: number;
|
||||
timestamp?: string | null;
|
||||
status?: string | null;
|
||||
recipient?: DirectusUser | string;
|
||||
sender?: DirectusUser | string | null;
|
||||
subject?: string;
|
||||
message?: string | null;
|
||||
collection?: string | null;
|
||||
item?: string | null;
|
||||
}
|
||||
|
||||
export interface DirectusShare {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
name?: string | null;
|
||||
collection?: DirectusCollection | string;
|
||||
item?: string;
|
||||
role?: DirectusRole | string | null;
|
||||
password?: string | null;
|
||||
user_created?: DirectusUser | string | null;
|
||||
date_created?: string | null;
|
||||
date_start?: string | null;
|
||||
date_end?: string | null;
|
||||
times_used?: number | null;
|
||||
max_uses?: number | null;
|
||||
}
|
||||
|
||||
export interface DirectusFlow {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
name?: string;
|
||||
icon?: string | null;
|
||||
color?: string | null;
|
||||
description?: string | null;
|
||||
status?: string;
|
||||
trigger?: string | null;
|
||||
accountability?: string | null;
|
||||
options?: 'json' | null;
|
||||
operation?: DirectusOperation | string | null;
|
||||
date_created?: string | null;
|
||||
user_created?: DirectusUser | string | null;
|
||||
operations?: DirectusOperation[] | string[];
|
||||
}
|
||||
|
||||
export interface DirectusOperation {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
name?: string | null;
|
||||
key?: string;
|
||||
type?: string;
|
||||
position_x?: number;
|
||||
position_y?: number;
|
||||
options?: 'json' | null;
|
||||
resolve?: DirectusOperation | string | null;
|
||||
reject?: DirectusOperation | string | null;
|
||||
flow?: DirectusFlow | string;
|
||||
date_created?: string | null;
|
||||
user_created?: DirectusUser | string | null;
|
||||
}
|
||||
|
||||
export interface DirectusTranslation {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
/** @required */
|
||||
language: string;
|
||||
/** @required */
|
||||
key: string;
|
||||
/** @required */
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface DirectusVersion {
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
key?: string;
|
||||
name?: string | null;
|
||||
collection?: DirectusCollection | string;
|
||||
item?: string;
|
||||
hash?: string | null;
|
||||
date_created?: string | null;
|
||||
date_updated?: string | null;
|
||||
user_created?: DirectusUser | string | null;
|
||||
user_updated?: DirectusUser | string | null;
|
||||
delta?: 'json' | null;
|
||||
}
|
||||
|
||||
export interface DirectusExtension {
|
||||
enabled?: boolean;
|
||||
/** @primaryKey */
|
||||
id: string;
|
||||
folder?: string;
|
||||
source?: string;
|
||||
bundle?: string | null;
|
||||
}
|
||||
|
||||
export interface Schema {
|
||||
article: Article[];
|
||||
article_tag: ArticleTag[];
|
||||
article_translations: ArticleTranslation[];
|
||||
global: Global;
|
||||
global_translations: GlobalTranslation[];
|
||||
languages: Language[];
|
||||
tag: Tag[];
|
||||
directus_access: DirectusAccess[];
|
||||
directus_activity: DirectusActivity[];
|
||||
directus_collections: DirectusCollection[];
|
||||
directus_comments: DirectusComment[];
|
||||
directus_fields: DirectusField[];
|
||||
directus_files: DirectusFile[];
|
||||
directus_folders: DirectusFolder[];
|
||||
directus_migrations: DirectusMigration[];
|
||||
directus_permissions: DirectusPermission[];
|
||||
directus_policies: DirectusPolicy[];
|
||||
directus_presets: DirectusPreset[];
|
||||
directus_relations: DirectusRelation[];
|
||||
directus_revisions: DirectusRevision[];
|
||||
directus_roles: DirectusRole[];
|
||||
directus_sessions: DirectusSession[];
|
||||
directus_settings: DirectusSettings;
|
||||
directus_users: DirectusUser[];
|
||||
directus_webhooks: DirectusWebhook[];
|
||||
directus_dashboards: DirectusDashboard[];
|
||||
directus_panels: DirectusPanel[];
|
||||
directus_notifications: DirectusNotification[];
|
||||
directus_shares: DirectusShare[];
|
||||
directus_flows: DirectusFlow[];
|
||||
directus_operations: DirectusOperation[];
|
||||
directus_translations: DirectusTranslation[];
|
||||
directus_versions: DirectusVersion[];
|
||||
directus_extensions: DirectusExtension[];
|
||||
}
|
||||
|
||||
export enum CollectionNames {
|
||||
article = 'article',
|
||||
article_tag = 'article_tag',
|
||||
article_translations = 'article_translations',
|
||||
global = 'global',
|
||||
global_translations = 'global_translations',
|
||||
languages = 'languages',
|
||||
tag = 'tag',
|
||||
directus_access = 'directus_access',
|
||||
directus_activity = 'directus_activity',
|
||||
directus_collections = 'directus_collections',
|
||||
directus_comments = 'directus_comments',
|
||||
directus_fields = 'directus_fields',
|
||||
directus_files = 'directus_files',
|
||||
directus_folders = 'directus_folders',
|
||||
directus_migrations = 'directus_migrations',
|
||||
directus_permissions = 'directus_permissions',
|
||||
directus_policies = 'directus_policies',
|
||||
directus_presets = 'directus_presets',
|
||||
directus_relations = 'directus_relations',
|
||||
directus_revisions = 'directus_revisions',
|
||||
directus_roles = 'directus_roles',
|
||||
directus_sessions = 'directus_sessions',
|
||||
directus_settings = 'directus_settings',
|
||||
directus_users = 'directus_users',
|
||||
directus_webhooks = 'directus_webhooks',
|
||||
directus_dashboards = 'directus_dashboards',
|
||||
directus_panels = 'directus_panels',
|
||||
directus_notifications = 'directus_notifications',
|
||||
directus_shares = 'directus_shares',
|
||||
directus_flows = 'directus_flows',
|
||||
directus_operations = 'directus_operations',
|
||||
directus_translations = 'directus_translations',
|
||||
directus_versions = 'directus_versions',
|
||||
directus_extensions = 'directus_extensions'
|
||||
}
|
||||
9
directus.ts
Normal file
9
directus.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { createDirectus, graphql, staticToken } from "@directus/sdk";
|
||||
import { DIRECTUS_TOKEN } from "astro:env/server";
|
||||
import type { Schema } from "./directus-schema";
|
||||
|
||||
const directus = createDirectus<Schema>("https://directus.yarkov.tech")
|
||||
.with(staticToken(DIRECTUS_TOKEN))
|
||||
.with(graphql());
|
||||
|
||||
export default directus;
|
||||
10
netlify.toml
10
netlify.toml
@ -1,10 +0,0 @@
|
||||
[build]
|
||||
command = "npm run build"
|
||||
publish = "dist"
|
||||
functions = "netlify/functions"
|
||||
|
||||
[[redirects]]
|
||||
from = "/api/*" # simplify all calls to serverless functions
|
||||
to = "/.netlify/functions/:splat" # all function calls will go to this path
|
||||
status = 200 # ok code
|
||||
force = true # ensure to always redirect
|
||||
@ -1,35 +0,0 @@
|
||||
import type { Handler } from "@netlify/functions";
|
||||
import { redisClient } from "../../redis";
|
||||
|
||||
const getViewsBySlug = async (slug: string): Promise<number> => {
|
||||
let views = 1;
|
||||
const data = await redisClient.get(`views:${slug}`);
|
||||
if (data) views = Number.parseInt(data, 10);
|
||||
if (Number.isNaN(views)) views = 1;
|
||||
return views;
|
||||
};
|
||||
|
||||
const handler: Handler = async (event) => {
|
||||
const slug = event.queryStringParameters?.slug;
|
||||
|
||||
switch (event.httpMethod) {
|
||||
case "GET": {
|
||||
if (!slug) return { statusCode: 400, body: "Bad request." };
|
||||
const views = await getViewsBySlug(slug);
|
||||
return { statusCode: 200, body: views.toString() };
|
||||
}
|
||||
case "POST": {
|
||||
if (!slug) return { statusCode: 400, body: "Bad request." };
|
||||
const views = await redisClient.incr(`views:${slug}`);
|
||||
return { statusCode: 200, body: views.toString() };
|
||||
}
|
||||
default: {
|
||||
return {
|
||||
statusCode: 500,
|
||||
body: "Unrecognized HTTP Method, must be one of GET/POST",
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export { handler };
|
||||
24187
package-lock.json
generated
24187
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -17,20 +17,20 @@
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/rss": "^3.0.0",
|
||||
"@astrojs/sitemap": "^3.0.0",
|
||||
"@astrojs/solid-js": "^3.0.1",
|
||||
"@astrojs/check": "^0.9.5",
|
||||
"@astrojs/node": "^9.5.0",
|
||||
"@astrojs/rss": "^4.0.13",
|
||||
"@astrojs/sitemap": "^3.6.0",
|
||||
"@astrojs/solid-js": "^5.1.3",
|
||||
"@directus/sdk": "^20.1.1",
|
||||
"@iconify-json/mdi": "^1.2.3",
|
||||
"@netlify/functions": "^2.1.0",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"astro": "^3.2.0",
|
||||
"astro": "^5.15.8",
|
||||
"astro-icon": "^1.1.5",
|
||||
"decap-cms-app": "^3.6.3",
|
||||
"hast-util-to-string": "^3.0.0",
|
||||
"hastscript": "^8.0.0",
|
||||
"html-escaper": "^3.0.3",
|
||||
"ioredis": "^5.3.2",
|
||||
"mime-types": "^2.1.35",
|
||||
"quicklink": "^3.0.1",
|
||||
"rehype-autolink-headings": "^7.0.0",
|
||||
|
||||
@ -1,249 +0,0 @@
|
||||
editor:
|
||||
preview: false
|
||||
publish_mode: editorial_workflow
|
||||
site_url: https://yarkov.tech
|
||||
display_url: https://yarkov.tech
|
||||
i18n:
|
||||
locales: [ru, en]
|
||||
default_locale: ru
|
||||
structure: multiple_folders
|
||||
locale: en
|
||||
backend:
|
||||
name: github
|
||||
repo: sergeyyarkov/yarkov.tech
|
||||
branch: main
|
||||
media_folder: public/media
|
||||
public_folder: "/media"
|
||||
collections:
|
||||
- name: articles
|
||||
label: Публикации
|
||||
label_singular: публикацию
|
||||
description: Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой
|
||||
folder: src/content/blog
|
||||
slug: "{{slug}}"
|
||||
create: true
|
||||
delete: true
|
||||
i18n: true
|
||||
fields:
|
||||
- name: coverImage
|
||||
widget: image
|
||||
label: Постер
|
||||
required: false
|
||||
i18n: true
|
||||
- name: draft
|
||||
label: В черновике
|
||||
widget: boolean
|
||||
hint: Опубликована ли статья
|
||||
i18n: true
|
||||
required: false
|
||||
- name: author
|
||||
widget: relation
|
||||
value_field: "{{firstName}} {{lastName}}"
|
||||
search_fields:
|
||||
- firstName
|
||||
- lastName
|
||||
collection: authors
|
||||
label: Автор
|
||||
i18n: true
|
||||
- name: title
|
||||
widget: string
|
||||
label: Заголовок
|
||||
i18n: true
|
||||
- name: description
|
||||
widget: string
|
||||
label: Описание
|
||||
i18n: true
|
||||
- name: tags
|
||||
widget: relation
|
||||
label: Тэги
|
||||
collection: tags
|
||||
multiple: true
|
||||
value_field: title
|
||||
search_fields:
|
||||
- title
|
||||
i18n: true
|
||||
- name: pubDate
|
||||
widget: datetime
|
||||
label: Дата публикации
|
||||
picker_utc: true
|
||||
i18n: true
|
||||
- name: updatedDate
|
||||
widget: datetime
|
||||
label: Дата обновления
|
||||
picker_utc: true
|
||||
i18n: true
|
||||
- name: body
|
||||
widget: markdown
|
||||
label: Содержание
|
||||
i18n: true
|
||||
- name: tags
|
||||
label: Тэги
|
||||
label_singular: тэг
|
||||
description: Используются для тегирования контента
|
||||
folder: src/content/tags
|
||||
create: true
|
||||
delete: true
|
||||
fields:
|
||||
- name: title
|
||||
widget: string
|
||||
label: Название
|
||||
required: true
|
||||
- name: authors
|
||||
label: Авторы
|
||||
label_singular: автора
|
||||
description: На странице статьи отображается имя автора
|
||||
slug: "{{firstName}}-{{lastName}}"
|
||||
folder: src/content/authors
|
||||
create: true
|
||||
delete: true
|
||||
i18n: true
|
||||
fields:
|
||||
- label: Имя
|
||||
name: firstName
|
||||
widget: string
|
||||
required: true
|
||||
i18n: true
|
||||
- label: Фамилия
|
||||
name: lastName
|
||||
widget: string
|
||||
required: true
|
||||
i18n: true
|
||||
- label: Об авторе
|
||||
name: body
|
||||
widget: markdown
|
||||
required: false
|
||||
i18n: true
|
||||
- name: projects
|
||||
label: Проекты
|
||||
label_singular: проект
|
||||
description: Основные проекты, которые были разработаны в выложены в открытый
|
||||
доступ
|
||||
folder: src/content/projects
|
||||
create: true
|
||||
delete: true
|
||||
i18n: true
|
||||
fields:
|
||||
- name: icon
|
||||
label: Иконка
|
||||
widget: string
|
||||
required: true
|
||||
i18n: true
|
||||
- name: title
|
||||
label: Название
|
||||
widget: string
|
||||
required: true
|
||||
i18n: true
|
||||
- name: year
|
||||
label: В каком году разработал
|
||||
widget: number
|
||||
required: true
|
||||
i18n: true
|
||||
- name: description
|
||||
label: Описание
|
||||
widget: string
|
||||
required: true
|
||||
i18n: true
|
||||
- name: sourceUrl
|
||||
label: Ссылка на исходник
|
||||
widget: string
|
||||
required: true
|
||||
i18n: true
|
||||
- name: demoUrl
|
||||
label: Ссылка на демонстрацию
|
||||
widget: string
|
||||
required: false
|
||||
i18n: true
|
||||
- name: articleUrl
|
||||
label: Ссылка на статью
|
||||
widget: string
|
||||
required: false
|
||||
i18n: true
|
||||
- name: skills
|
||||
label: Навыки
|
||||
label_singular: навык
|
||||
folder: src/content/skills
|
||||
create: true
|
||||
delete: true
|
||||
description: Навыки отображаются на странице Обо мне
|
||||
i18n: true
|
||||
fields:
|
||||
- name: title
|
||||
label: Категория
|
||||
widget: string
|
||||
required: true
|
||||
i18n: true
|
||||
- name: list
|
||||
label: Записи
|
||||
required: true
|
||||
widget: list
|
||||
allow_add: true
|
||||
min: 1
|
||||
i18n: true
|
||||
fields:
|
||||
- name: icon
|
||||
label: Иконка
|
||||
widget: string
|
||||
i18n: true
|
||||
required: false
|
||||
- name: title
|
||||
label: Название
|
||||
widget: string
|
||||
i18n: true
|
||||
- name: settings
|
||||
label: Настройки
|
||||
files:
|
||||
- name: siteconfig
|
||||
label: Настройки веб-сайта
|
||||
file: siteconfig.json
|
||||
fields:
|
||||
- label: Название сайта
|
||||
name: name
|
||||
widget: string
|
||||
hint: Отображается в шапке.
|
||||
default: yarkov.tech
|
||||
- label: Автор веб-сайта
|
||||
name: author
|
||||
widget: string
|
||||
hint: Отображается в подвале.
|
||||
- label: Глобальный заголовок
|
||||
name: globalTitle
|
||||
widget: string
|
||||
hint: Отображется во вкладке браузера.
|
||||
- label: В разработке
|
||||
name: isSiteUnderConstruction
|
||||
widget: boolean
|
||||
required: false
|
||||
default: false
|
||||
hint: Отображает баннер на всех старницах о том, что веб-сайт находится в
|
||||
разработке
|
||||
- label: Счетчик Яндекс.Метрики
|
||||
name: ymCounter
|
||||
widget: number
|
||||
hint: "Например: 90034656"
|
||||
required: false
|
||||
- label: Статьи
|
||||
name: articles
|
||||
widget: object
|
||||
fields:
|
||||
- name: recentLimit
|
||||
label: Лимит на отображение
|
||||
widget: number
|
||||
hint: Кол-во публикаций на гл.странице
|
||||
default: 5
|
||||
- label: Контакты
|
||||
name: contacts
|
||||
widget: object
|
||||
required: false
|
||||
fields:
|
||||
- label: Telegram
|
||||
name: telegram
|
||||
widget: string
|
||||
required: false
|
||||
- label: Почта
|
||||
name: email
|
||||
widget: string
|
||||
required: false
|
||||
- label: Github
|
||||
name: github
|
||||
widget: string
|
||||
required: false
|
||||
9
redis.ts
9
redis.ts
@ -1,9 +0,0 @@
|
||||
import Redis from "ioredis";
|
||||
|
||||
const redisClient = new Redis({
|
||||
host: process.env.REDIS_HOST,
|
||||
port: Number.parseInt(process.env.REDIS_PORT || "6379", 10),
|
||||
password: process.env.REDIS_PASSWORD,
|
||||
});
|
||||
|
||||
export { redisClient };
|
||||
@ -4,18 +4,18 @@ import { URL_BLOG_PREFIX } from "@root/constants";
|
||||
import "./ArticleItem.scss";
|
||||
|
||||
export type ArticleItemProps = {
|
||||
id: string;
|
||||
id: number;
|
||||
title: string;
|
||||
pubDate: Date;
|
||||
pageLang: string;
|
||||
};
|
||||
|
||||
const ArticleItem: Component<ArticleItemProps> = (props) => {
|
||||
const articleLang = props.id.split("/")[0];
|
||||
const href = createRelativeArticleUrl(
|
||||
{ id: props.id, title: props.title, pubDate: props.pubDate },
|
||||
URL_BLOG_PREFIX
|
||||
);
|
||||
const articleLang = "ru";
|
||||
// const href = createRelativeArticleUrl(
|
||||
// { id: props.id, title: props.title, pubDate: props.pubDate },
|
||||
// URL_BLOG_PREFIX
|
||||
// );
|
||||
|
||||
return (
|
||||
<article
|
||||
@ -24,14 +24,14 @@ const ArticleItem: Component<ArticleItemProps> = (props) => {
|
||||
itemtype="http://schema.org/BlogPosting"
|
||||
class="article-item"
|
||||
>
|
||||
<a href={href}>
|
||||
<a href={""}>
|
||||
<div class="flex">
|
||||
<h3 itemprop="headline">{props.title}</h3>
|
||||
{articleLang !== props.pageLang && <sup>{articleLang.toLocaleUpperCase()}</sup>}
|
||||
</div>
|
||||
<p>
|
||||
<time datetime={props.pubDate.toISOString()}>
|
||||
{createDateFormatter(props.pageLang).format(props.pubDate)}
|
||||
<time datetime={`props.pubDate.toISOString()`}>
|
||||
{/* {createDateFormatter(props.pageLang).format(props.pubDate)} */}
|
||||
</time>
|
||||
</p>
|
||||
</a>
|
||||
|
||||
@ -9,13 +9,13 @@ import TranslatedLink from "@components/TranslatedLink.astro";
|
||||
---
|
||||
|
||||
<header {...IS_SITE_UNDER_CONSTRUCTION ? { style: "top: 45px;" } : {}}>
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<TranslatedLink to="/">
|
||||
<div class='container'>
|
||||
<div class='logo'>
|
||||
<TranslatedLink to='/'>
|
||||
{SITE_METADATA.name}
|
||||
</TranslatedLink>
|
||||
</div>
|
||||
<nav itemscope itemtype="http://schema.org/SiteNavigationElement">
|
||||
<nav itemscope itemtype='http://schema.org/SiteNavigationElement'>
|
||||
<ul>
|
||||
{
|
||||
SITE_METADATA.nav.map((link) => (
|
||||
@ -23,8 +23,7 @@ import TranslatedLink from "@components/TranslatedLink.astro";
|
||||
<TranslatedLink
|
||||
itemprop={"url"}
|
||||
to={link.url}
|
||||
class:list={[{ active: Astro.url.pathname.includes(link.url) }]}
|
||||
>
|
||||
class:list={[{ active: Astro.url.pathname.includes(link.url) }]}>
|
||||
<UIString key={link.key} />
|
||||
</TranslatedLink>
|
||||
</li>
|
||||
@ -33,23 +32,23 @@ import TranslatedLink from "@components/TranslatedLink.astro";
|
||||
</ul>
|
||||
{
|
||||
SITE_METADATA.contacts && (
|
||||
<div class="contacts">
|
||||
<a target="_blank" href={"mailto:" + SITE_METADATA.contacts.email}>
|
||||
<div class='contacts'>
|
||||
<a target='_blank' href={"mailto:" + SITE_METADATA.contacts.email}>
|
||||
Email
|
||||
<Icon name="email" width="18" height="18" />
|
||||
<Icon name='email' width='18' height='18' />
|
||||
</a>
|
||||
<a target="_blank" href={SITE_METADATA.contacts.github}>
|
||||
<a target='_blank' href={SITE_METADATA.contacts.github}>
|
||||
Github
|
||||
<Icon name="github_filled" width="18" height="18" />
|
||||
<Icon name='github_filled' width='18' height='18' />
|
||||
</a>
|
||||
<a target="_blank" href={SITE_METADATA.contacts.telegram}>
|
||||
<a target='_blank' href={SITE_METADATA.contacts.telegram}>
|
||||
Telegram
|
||||
<Icon name="telegram" width="18" height="18" />
|
||||
<Icon name='telegram' width='18' height='18' />
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div class="flex settings">
|
||||
<div class='flex settings'>
|
||||
<LanguageSelect />
|
||||
<ThemeSwitcher client:visible />
|
||||
</div>
|
||||
@ -58,7 +57,7 @@ import TranslatedLink from "@components/TranslatedLink.astro";
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang='scss'>
|
||||
header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import siteconfig from "siteconfig.json";
|
||||
import { getLanguageFromURL } from "@i18n/utils";
|
||||
import * as utils from "@utils/index";
|
||||
@ -7,13 +6,32 @@ import ArticleItem from "@components/ArticleItem";
|
||||
import EmptyList from "@components/EmptyList.astro";
|
||||
import UIString from "@components/UIString.astro";
|
||||
import TranslatedLink from "@components/TranslatedLink.astro";
|
||||
import directus from "@/directus";
|
||||
import type { ArticleTranslation } from "@/directus-schema";
|
||||
|
||||
export interface Props {
|
||||
articles: CollectionEntry<"blog">[];
|
||||
length?: number | undefined;
|
||||
}
|
||||
|
||||
const { articles, length = siteconfig.articles.recentLimit } = Astro.props as Props;
|
||||
type RecentArticlesQueryResult = {
|
||||
article_translations: Pick<ArticleTranslation, "id" | "title" | "pub_date">[];
|
||||
};
|
||||
|
||||
const data = await directus.query<RecentArticlesQueryResult>(`
|
||||
query Article_translations {
|
||||
article_translations {
|
||||
id
|
||||
title
|
||||
pub_date
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const { article_translations: articles } = data;
|
||||
|
||||
console.log(data);
|
||||
|
||||
const { length = siteconfig.articles.recentLimit } = Astro.props as Props;
|
||||
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
||||
const filtered = utils.removeDuplicates(articles.slice(0, length), pageLang);
|
||||
const isEmpty = articles.length === 0;
|
||||
@ -24,18 +42,18 @@ const isEmpty = articles.length === 0;
|
||||
<h2>
|
||||
<UIString key={"recentArticles.heading"} />
|
||||
</h2>
|
||||
<TranslatedLink to="/articles/">
|
||||
<TranslatedLink to='/articles/'>
|
||||
<UIString key={"recentArticles.all"} />
|
||||
</TranslatedLink>
|
||||
</div>
|
||||
<div itemscope itemtype="http://schema.org/Blog">
|
||||
<div itemscope itemtype='http://schema.org/Blog'>
|
||||
{
|
||||
!isEmpty ? (
|
||||
filtered.map((article) => (
|
||||
articles.map((article) => (
|
||||
<ArticleItem
|
||||
id={article.id}
|
||||
title={article.data.title}
|
||||
pubDate={article.data.pubDate}
|
||||
title={article.title}
|
||||
pubDate={article.pub_date}
|
||||
pageLang={pageLang}
|
||||
/>
|
||||
))
|
||||
@ -46,7 +64,7 @@ const isEmpty = articles.length === 0;
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang='scss'>
|
||||
section {
|
||||
& > div:nth-child(1) {
|
||||
display: flex;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { getCollection } from "astro:content";
|
||||
import { getCollection, getEntry, render } from "astro:content";
|
||||
import slugify from "@sindresorhus/slugify";
|
||||
import ArticleLayout from "@root/layouts/article.astro";
|
||||
import { createRelativeArticleUrl, removeLanguageCodeFromPath } from "@root/utils";
|
||||
|
||||
@ -9,37 +10,41 @@ import { createRelativeArticleUrl, removeLanguageCodeFromPath } from "@root/util
|
||||
* The final url will be `http://website.com/blog/2023-01-01/my-article` with default language
|
||||
* and `http://website.com/{language-code}/blog/2023-01-01/my-article` with other languages.
|
||||
*/
|
||||
export async function getStaticPaths() {
|
||||
const collection = await getCollection("blog", (e) => !e.data.draft);
|
||||
return collection.map((article) => {
|
||||
const {
|
||||
id,
|
||||
data: { title, pubDate },
|
||||
} = article;
|
||||
const url = createRelativeArticleUrl({ id, title, pubDate });
|
||||
return {
|
||||
params: { blog: url.slice(1) },
|
||||
props: {
|
||||
article,
|
||||
availableOnLangs: collection.filter((e) =>
|
||||
e.id.includes(removeLanguageCodeFromPath(article.id))
|
||||
),
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
// export async function getStaticPaths() {
|
||||
// const collection = await getCollection("blog", (e) => !e.data.draft);
|
||||
// return collection.map((article) => {
|
||||
// const {
|
||||
// id,
|
||||
// data: { title, pubDate },
|
||||
// } = article;
|
||||
// const url = createRelativeArticleUrl({ id, title, pubDate });
|
||||
// return {
|
||||
// params: { blog: url.slice(1) },
|
||||
// props: {
|
||||
// article,
|
||||
// availableOnLangs: collection.filter((e) =>
|
||||
// e.id.includes(removeLanguageCodeFromPath(article.id))
|
||||
// ),
|
||||
// },
|
||||
// };
|
||||
// });
|
||||
// }
|
||||
|
||||
type Props = { article: CollectionEntry<"blog">; availableOnLangs: CollectionEntry<"blog">[] };
|
||||
|
||||
const { Content, headings } = await Astro.props.article.render();
|
||||
const { article, availableOnLangs } = Astro.props;
|
||||
const { blog } = Astro.params as { blog: string };
|
||||
const collection = await getCollection("blog", (e) => !e.data.draft);
|
||||
const slug = blog.split("/").at(-1);
|
||||
const article = collection.find(
|
||||
(a) => slugify(a.slug.split("/").at(-1) || "", { lowercase: true }) === slug
|
||||
);
|
||||
|
||||
if (article === undefined) return Astro.redirect("/404");
|
||||
|
||||
const { Content, headings } = await render(article);
|
||||
// const { article, availableOnLangs } = Astro.props;
|
||||
---
|
||||
|
||||
<ArticleLayout
|
||||
lang={article.id.split("/")[0]}
|
||||
article={article}
|
||||
headings={headings}
|
||||
availableOnLangs={availableOnLangs}
|
||||
>
|
||||
<ArticleLayout lang={article.id.split("/")[0]} article={article} headings={headings}>
|
||||
<Content />
|
||||
</ArticleLayout>
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<link href="/admin/config.yml" type="text/yaml" rel="cms-config-url" />
|
||||
<title>Content Manager</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://unpkg.com/decap-cms@^3.1.2/dist/decap-cms.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -5,13 +5,27 @@ import * as utils from "@utils/index";
|
||||
import PageLayout from "@layouts/default.astro";
|
||||
import PageHeading from "@components/PageHeading.astro";
|
||||
import ArticlesList from "@root/components/ArticlesList";
|
||||
import directus from "@/directus";
|
||||
|
||||
const t = useTranslation(Astro);
|
||||
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
||||
const articles = await getCollection("blog", (e) => !e.data.draft);
|
||||
const tags = Array.from(new Set((await getCollection("tags")).map((t) => t.data.title)));
|
||||
const filtered = utils.removeDuplicates(articles, pageLang);
|
||||
// const articles = await getCollection("blog", (e) => !e.data.draft);
|
||||
// const filtered = utils.removeDuplicates(articles, pageLang);
|
||||
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
||||
const tags = (await directus.query(`query Tag { tag { title } }`)).tag.map((t) => t.title);
|
||||
|
||||
const { article_translations } = await directus.query(`
|
||||
query Article_translations {
|
||||
article_translations {
|
||||
languages_code {
|
||||
code
|
||||
}
|
||||
slug
|
||||
status
|
||||
pub_date
|
||||
}
|
||||
}
|
||||
`);
|
||||
---
|
||||
|
||||
<PageLayout
|
||||
@ -25,7 +39,7 @@ const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
||||
<ArticlesList
|
||||
client:load
|
||||
i18n={{ "articles.empty": t("articles.empty"), "input.search": t("input.search") }}
|
||||
articles={utils.formatToArticleBlocks(filtered)}
|
||||
articles={utils.formatToArticleBlocks(article_translations)}
|
||||
tags={tags}
|
||||
pageLang={pageLang}
|
||||
/>
|
||||
|
||||
@ -11,9 +11,6 @@ import { getLanguageFromURL, useTranslation } from "@root/i18n/utils";
|
||||
|
||||
const pageLang = getLanguageFromURL(Astro.url.pathname);
|
||||
const t = useTranslation(Astro);
|
||||
const articles = (await getCollection("blog", (e) => !e.data.draft)).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
|
||||
);
|
||||
---
|
||||
|
||||
<PageLayout description={t("site.description")} lang={pageLang}>
|
||||
@ -26,11 +23,11 @@ const articles = (await getCollection("blog", (e) => !e.data.draft)).sort(
|
||||
<p><UIString key={"splash.description"} /></p>
|
||||
</SplashHeading>
|
||||
<SplashLinks>
|
||||
<SplashLink icon="information" href="/about/"><UIString key={"splash.about"} /></SplashLink>
|
||||
<SplashLink icon="email_filled" href="/contacts/">
|
||||
<SplashLink icon='information' href='/about/'><UIString key={"splash.about"} /></SplashLink>
|
||||
<SplashLink icon='email_filled' href='/contacts/'>
|
||||
<UIString key={"splash.contact"} />
|
||||
</SplashLink>
|
||||
</SplashLinks>
|
||||
</Splash>
|
||||
<RecentArticles articles={articles} />
|
||||
<RecentArticles />
|
||||
</PageLayout>
|
||||
|
||||
@ -48,13 +48,13 @@ export function createRelativeArticleUrl(
|
||||
export function formatToArticleBlocks(articles: CollectionEntry<"blog">[]) {
|
||||
const blocks: Record<string, any[]> = {};
|
||||
articles.forEach((a) => {
|
||||
const year = a.data.pubDate.getFullYear();
|
||||
const year = new Date(a.pub_date).getFullYear();
|
||||
if (!blocks[year]) blocks[year] = [];
|
||||
blocks[year].push({
|
||||
id: a.id,
|
||||
title: a.data.title,
|
||||
tags: a.data.tags,
|
||||
pubDate: a.data.pubDate,
|
||||
title: a.title,
|
||||
// tags: a.tags,
|
||||
pubDate: a.pub_date,
|
||||
});
|
||||
});
|
||||
return blocks;
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"include": [".astro/types.d.ts", "**/*"],
|
||||
"exclude": ["dist"],
|
||||
"exclude": ["dist"],
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"@root/*": ["./src/*"],
|
||||
"@styles/*": ["./src/styles/*"],
|
||||
"@components/*": ["./src/components/*"],
|
||||
@ -19,5 +20,5 @@
|
||||
"typeRoots": ["./node_modules/@types", "./src/types"],
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user