- className={ 'h-full w-full rounded-3xl backdrop-blur align-middle grid grid-cols-2 content-center' }>
+
+
Atelier Lumiaethor
+
In pursuit of absolute
+ simplicity and ultimate
+ sophistication
+
-
-
- test
+
+
+
+ { !isSm &&
+
+
+
+ © 2024-{ new Date().getFullYear() } Lumither Tao
+
+
Powered by Next.js and Rust, built with passion and love
+
LMTCloud ecosystem
+
+
+ }
+
+
+
+ {
+ entries.map((meta, key) => (
+ -
+
+
+ ))
+ }
+
-
-
-
-
- {
- entries.map((meta, key) => (
- -
-
-
- ))
- }
-
-
+
);
}
diff --git a/frontend/components/BackgroundBox.tsx b/frontend/components/BackgroundBox.tsx
deleted file mode 100644
index 295074f..0000000
--- a/frontend/components/BackgroundBox.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-'use client';
-import React from 'react';
-import { motion } from 'motion/react';
-import { cn } from '@/src/utils';
-
-export const BoxesCore = ({ className, ...rest }: { className?: string }) => {
- const rows = new Array(250).fill(1);
- const cols = new Array(200).fill(1);
- let colors = [
- '#93c5fd',
- '#f9a8d4',
- '#86efac',
- '#fde047',
- '#fca5a5',
- '#d8b4fe',
- '#93c5fd',
- '#a5b4fc',
- '#c4b5fd'
- ];
- const getRandomColor = () => {
- return colors[Math.floor(Math.random() * colors.length)];
- };
-
- return (
-
- { rows.map((_, i) => (
-
- { cols.map((_, j) => (
-
- { j % 2 === 0 && i % 2 === 0 ? (
-
- ) : null }
-
- )) }
-
- )) }
-
- );
-};
-
-export const Boxes = React.memo(BoxesCore);
diff --git a/frontend/components/BackgroundBoxGL.tsx b/frontend/components/BackgroundBoxGL.tsx
deleted file mode 100644
index 7f26ed0..0000000
--- a/frontend/components/BackgroundBoxGL.tsx
+++ /dev/null
@@ -1,266 +0,0 @@
-'use client';
-import React, { useEffect, useRef } from 'react';
-
-// WebGL-based rewrite of the grid/hover effect originally implemented with many DOM nodes.
-// Key design goals:
-// - zero per-cell DOM; a single full-screen draw with a fragment shader
-// - hover color derived deterministically from a small palette
-// - optional CSS transform to match the original perspective/skew
-// - high-DPI aware; resizes with container
-
-export default function BoxesGL({
- className,
- style,
- rows = 250,
- cols = 200,
- lineWidth = 1.0, // device pixels
- transformLikeOriginal = true
-}: {
- className?: string
- style?: React.CSSProperties
- rows?: number
- cols?: number
- lineWidth?: number
- transformLikeOriginal?: boolean
-}) {
- const canvasRef = useRef
(null);
- const rafRef = useRef(null);
- const mouseRef = useRef<{ x: number; y: number } | null>(null);
-
- useEffect(() => {
- const canvas = canvasRef.current!;
- const gl = canvas.getContext('webgl2', { antialias: false, premultipliedAlpha: true });
- if (!gl) {
- console.warn('WebGL2 not available');
- // Fail closed; nothing to do if WebGL2 is unavailable
- return;
- }
-
- // Create program (fullscreen triangle)
- const vs = gl.createShader(gl.VERTEX_SHADER)!;
- gl.shaderSource(
- vs,
- `#version 300 es\n
- const vec2 verts[3] = vec2[3](
- vec2(-1.0, -1.0),
- vec2(3.0, -1.0),
- vec2(-1.0, 3.0)
- );
- void main(){
- gl_Position = vec4(verts[gl_VertexID], 0.0, 1.0);
- }
- `
- );
- gl.compileShader(vs);
-
- const fs = gl.createShader(gl.FRAGMENT_SHADER)!;
- gl.shaderSource(
- fs,
- `#version 300 es\n
- precision highp float;
- out vec4 o;
-
- uniform vec2 u_resolution; // canvas size in device pixels
- uniform vec2 u_mouse; // mouse in device pixels, (-1,-1) if outside
- uniform float u_time; // seconds
- uniform float u_rows;
- uniform float u_cols;
- uniform float u_lineWidth; // in device pixels
-
- // Border color and plus sign color (matches tailwind slate-700-ish)
- const vec3 BORDER = vec3(0.22, 0.27, 0.33);
- const vec3 PLUS = vec3(0.22, 0.27, 0.33);
-
- // A small pastel palette like the original
- vec3 palette(int idx){
- // 9-color palette
- if(idx==0) return vec3(0.576,0.773,0.992);
- if(idx==1) return vec3(0.976,0.659,0.831);
- if(idx==2) return vec3(0.525,0.937,0.675);
- if(idx==3) return vec3(0.992,0.878,0.278);
- if(idx==4) return vec3(0.988,0.648,0.648);
- if(idx==5) return vec3(0.847,0.706,0.996);
- if(idx==6) return vec3(0.576,0.773,0.992);
- if(idx==7) return vec3(0.647,0.706,0.988);
- return vec3(0.769,0.710,0.992);
- }
-
- // Hash helpers for stable per-cell randomness
- float hash11(float x){
- x = fract(x * 0.1031);
- x *= x + 33.33;
- return fract(1e4 * x * (x + 0.33));
- }
- float hash21(vec2 p){
- vec3 p3 = fract(vec3(p.xyx) * 0.1031);
- p3 += dot(p3, p3.yzx + 33.33);
- return fract((p3.x + p3.y) * p3.z);
- }
-
- void main(){
- vec2 frag = gl_FragCoord.xy; // device pixels
- vec2 gridSize = vec2(u_cols, u_rows);
- vec2 cellSize = u_resolution / gridSize; // pixels per cell
-
- // Compute integer cell coordinates and local position within cell [0,1)
- vec2 uvGrid = frag / u_resolution * gridSize;
- vec2 cellId = floor(uvGrid);
- vec2 cellUV = fract(uvGrid);
-
- // Grid lines: draw top+right borders to mimic original (border-t, border-r, border-l on first col)
- float lw = u_lineWidth / max(cellSize.x, 1.0); // convert to relative width in [0,1] axis
- float lwY = u_lineWidth / max(cellSize.y, 1.0);
-
- float lineTop = step(1.0 - lwY, cellUV.y);
- float lineRight= step(1.0 - lw , cellUV.x);
- float lineLeft = step(cellUV.x, lw) * step(0.5, step(0.0, cellId.x)); // left border for all cols via small bias
-
- float lineMask = max(lineTop, max(lineRight, lineLeft));
-
- // Determine hovered cell index
- vec2 hoverCell = vec2(-1.0);
- bool hovering = u_mouse.x >= 0.0 && u_mouse.y >= 0.0;
- if(hovering){
- vec2 hoverUVGrid = u_mouse / u_resolution * gridSize;
- hoverCell = floor(hoverUVGrid);
- }
- bool isHover = hovering && all(equal(hoverCell, cellId));
-
- // Background: transparent unless hovered. On hover, fill with palette color chosen by cell hash.
- vec3 bg = vec3(0.0);
- float alpha = 0.0;
- if(isHover){
- // Stable color per cell, with slight time wobble to avoid banding on long hovers
- float h = hash21(cellId + vec2(floor(u_time*0.25)));
- int idx = int(floor(h * 9.0)) % 9;
- bg = palette(idx);
- alpha = 1.0;
- }
-
- // Plus sign for even-even cells: thin cross centered
- bool evenEven = mod(cellId.x, 2.0) < 0.5 && mod(cellId.y, 2.0) < 0.5;
- float plusThicknessX = 0.5 * u_lineWidth / max(cellSize.x, 1.0);
- float plusThicknessY = 0.5 * u_lineWidth / max(cellSize.y, 1.0);
- float cross = 0.0;
- if(evenEven){
- float vert = step(0.5 - plusThicknessX, abs(cellUV.x - 0.5));
- float hori = step(0.5 - plusThicknessY, abs(cellUV.y - 0.5));
- cross = 1.0 - max(vert, hori);
- }
-
- vec3 color = mix(bg, BORDER, max(lineMask, 0.0));
- color = mix(color, PLUS, cross);
- float a = max(alpha, max(lineMask, cross));
-
- o = vec4(color, a);
- }
- `
- );
- gl.compileShader(fs);
-
- const prog = gl.createProgram()!;
- gl.attachShader(prog, vs);
- gl.attachShader(prog, fs);
- gl.linkProgram(prog);
-
- // Check compile/link for diagnostics (silent in prod; could surface to console in dev)
- if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
- console.warn('WebGL program link error:', gl.getProgramInfoLog(prog));
- }
-
- gl.useProgram(prog);
-
- const uResolution = gl.getUniformLocation(prog, 'u_resolution');
- const uMouse = gl.getUniformLocation(prog, 'u_mouse');
- const uTime = gl.getUniformLocation(prog, 'u_time');
- const uRows = gl.getUniformLocation(prog, 'u_rows');
- const uCols = gl.getUniformLocation(prog, 'u_cols');
- const uLineWidth = gl.getUniformLocation(prog, 'u_lineWidth');
-
- // Single draw call state
- gl.disable(gl.DEPTH_TEST);
- gl.disable(gl.CULL_FACE);
- gl.viewport(0, 0, canvas.width, canvas.height);
-
- // Resize handling (devicePixelRatio-aware)
- const resize = () => {
- const dpr = Math.max(window.devicePixelRatio || 1, 1);
- const { clientWidth, clientHeight } = canvas;
- const w = Math.max(1, Math.floor(clientWidth * dpr));
- const h = Math.max(1, Math.floor(clientHeight * dpr));
- if (canvas.width !== w || canvas.height !== h) {
- canvas.width = w;
- canvas.height = h;
- gl.viewport(0, 0, w, h);
- }
- };
-
- const observer = new ResizeObserver(resize);
- observer.observe(canvas);
- resize();
-
- // Mouse tracking in device pixels
- const onMove = (e: PointerEvent) => {
- const rect = canvas.getBoundingClientRect();
- const dpr = Math.max(window.devicePixelRatio || 1, 1);
- const x = (e.clientX - rect.left) * dpr;
- const y = (rect.bottom - e.clientY) * dpr; // flip Y to GL coords
- mouseRef.current = { x, y };
- };
- const onLeave = () => {
- mouseRef.current = null;
- };
- canvas.addEventListener('pointermove', onMove);
- canvas.addEventListener('pointerleave', onLeave);
-
- const t0 = performance.now();
- const tick = () => {
- const t = (performance.now() - t0) / 1000;
- gl.useProgram(prog);
- gl.uniform2f(uResolution, canvas.width, canvas.height);
- const m = mouseRef.current;
- if (m) gl.uniform2f(uMouse, m.x, m.y);
- else gl.uniform2f(uMouse, -1, -1);
- gl.uniform1f(uTime, t);
- gl.uniform1f(uRows, rows);
- gl.uniform1f(uCols, cols);
- gl.uniform1f(uLineWidth, lineWidth);
-
- gl.drawArrays(gl.TRIANGLES, 0, 3);
- rafRef.current = requestAnimationFrame(tick);
- };
- tick();
-
- return () => {
- if (rafRef.current) cancelAnimationFrame(rafRef.current);
- observer.disconnect();
- canvas.removeEventListener('pointermove', onMove);
- canvas.removeEventListener('pointerleave', onLeave);
- gl.deleteProgram(prog);
- gl.deleteShader(vs);
- gl.deleteShader(fs);
- };
- }, [ rows, cols, lineWidth ]);
-
- return (
-
-
-
- );
-}
diff --git a/frontend/components/ConstructionPlaceHolder.tsx b/frontend/components/ConstructionPlaceHolder.tsx
index 803d41a..40568a2 100644
--- a/frontend/components/ConstructionPlaceHolder.tsx
+++ b/frontend/components/ConstructionPlaceHolder.tsx
@@ -4,7 +4,7 @@ const ConstructionPlaceHolder = () => {
return (
- 正在施工中...
+ * Under Construction *
);
diff --git a/frontend/components/Footer.tsx b/frontend/components/Footer.tsx
index 5036a02..6418200 100644
--- a/frontend/components/Footer.tsx
+++ b/frontend/components/Footer.tsx
@@ -1,3 +1,5 @@
+'use client';
+
import React from 'react';
import Link from 'next/link';
import { IoLogoGithub } from 'react-icons/io5';
diff --git a/frontend/src/api/blog/post.ts b/frontend/src/api/blog/post.ts
index 5dedce7..f1046f8 100644
--- a/frontend/src/api/blog/post.ts
+++ b/frontend/src/api/blog/post.ts
@@ -26,9 +26,26 @@ export interface PostListResponse {
status: string
}
+interface FetchPostListParams {
+ page: number;
+ page_size?: number;
+ tag_filter?: string[];
+ match_all?: boolean;
+}
-export async function fetchPostList(page: number, page_size: number = DEFAULT_PAGE_SIZE): Promise {
- const url = `/blog/posts?page=${ page }&page_size=${ page_size }`;
+export async function fetchPostList({
+ page,
+ page_size = DEFAULT_PAGE_SIZE,
+ tag_filter = [],
+ match_all = false
+ }: FetchPostListParams
+): Promise {
+ const pagination_string = `page=${ page }&page_size=${ page_size }`;
+ const tag_filter_string = tag_filter.length != 0
+ ? `&tags=${ tag_filter.join(',') }&match_all=${ match_all }`
+ : '';
+
+ const url = `/blog/posts?${ pagination_string }${ tag_filter_string }`;
return await fetchNocturneJson(url);
}