mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
refactor(dashboard): crosshair schematic background for login
This commit is contained in:
@@ -10,24 +10,21 @@ import { onMounted, onUnmounted, ref } from "vue";
|
||||
const canvas = ref<HTMLCanvasElement | null>(null);
|
||||
let animId: number | null = null;
|
||||
|
||||
interface Cylinder {
|
||||
interface Cross {
|
||||
x: number;
|
||||
y: number;
|
||||
phase: number;
|
||||
}
|
||||
|
||||
const createGrid = (w: number, h: number): Cylinder[] => {
|
||||
const grid: Cylinder[] = [];
|
||||
const sx = 44, sy = 38;
|
||||
const cols = Math.ceil(w / sx) + 2;
|
||||
const rows = Math.ceil(h / sy) + 2;
|
||||
|
||||
for (let i = 0; i < cols; i++) {
|
||||
for (let j = 0; j < rows; j++) {
|
||||
const createGrid = (w: number, h: number): Cross[] => {
|
||||
const grid: Cross[] = [];
|
||||
const s = 32;
|
||||
for (let i = 0; i < Math.ceil(w / s) + 2; i++) {
|
||||
for (let j = 0; j < Math.ceil(h / s) + 2; j++) {
|
||||
grid.push({
|
||||
x: i * sx + (j % 2) * (sx / 2),
|
||||
y: j * sy,
|
||||
phase: (i + j * 0.5) * 0.3,
|
||||
x: i * s + (j % 2) * (s / 2),
|
||||
y: j * s * 0.75,
|
||||
phase: (i + j * 0.5) * 0.25,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -35,56 +32,48 @@ const createGrid = (w: number, h: number): Cylinder[] => {
|
||||
};
|
||||
|
||||
const draw = (ctx: CanvasRenderingContext2D, w: number, h: number, t: number) => {
|
||||
ctx.fillStyle = "#0c0e12";
|
||||
ctx.fillStyle = "#090a0d";
|
||||
ctx.fillRect(0, 0, w, h);
|
||||
|
||||
const sx = 44, sy = 38;
|
||||
const cols = Math.ceil(w / sx) + 2;
|
||||
const rows = Math.ceil(h / sy) + 2;
|
||||
const s = 32;
|
||||
const arm = 5;
|
||||
const barH = 2;
|
||||
const barW = 10;
|
||||
|
||||
for (let i = 0; i < cols; i++) {
|
||||
for (let j = 0; j < rows; j++) {
|
||||
const x = i * sx + (j % 2) * (sx / 2);
|
||||
const y = j * sy;
|
||||
for (let i = 0; i < Math.ceil(w / s) + 2; i++) {
|
||||
for (let j = 0; j < Math.ceil(h / (s * 0.75)) + 2; j++) {
|
||||
const x = i * s + (j % 2) * (s / 2);
|
||||
const y = j * s * 0.75;
|
||||
const pulse = 0.4 + 0.4 * Math.sin(t * 0.15 + (i + j) * 0.3);
|
||||
|
||||
// Outer rim
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 8, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "#1a1c22";
|
||||
ctx.fill();
|
||||
|
||||
// Recessed cylinder body
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 7, 0, Math.PI * 2);
|
||||
const bodyGrad = ctx.createRadialGradient(x, y - 2, 0, x, y, 7);
|
||||
bodyGrad.addColorStop(0, "#14161c");
|
||||
bodyGrad.addColorStop(1, "#0a0b0e");
|
||||
ctx.fillStyle = bodyGrad;
|
||||
ctx.fill();
|
||||
|
||||
// Sharp outer rim highlight
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 8, 0, Math.PI * 2);
|
||||
ctx.strokeStyle = "#2a2c34";
|
||||
// Recessed socket (square notch)
|
||||
ctx.strokeStyle = "#1a1c22";
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.strokeRect(x - 6, y - 6, 12, 12);
|
||||
|
||||
// Cross arms
|
||||
ctx.strokeStyle = "#1e2028";
|
||||
ctx.lineWidth = barH;
|
||||
ctx.lineCap = "square";
|
||||
// Horizontal
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - arm, y);
|
||||
ctx.lineTo(x + arm, y);
|
||||
ctx.stroke();
|
||||
// Vertical
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y - arm);
|
||||
ctx.lineTo(x, y + arm);
|
||||
ctx.stroke();
|
||||
|
||||
// Deep indigo glow from depth
|
||||
const depthPulse = 0.15 + 0.1 * Math.sin(t * 0.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 4, 0, Math.PI * 2);
|
||||
const glowGrad = ctx.createRadialGradient(x, y, 0, x, y, 4);
|
||||
glowGrad.addColorStop(0, `rgba(60, 40, 120, ${depthPulse})`);
|
||||
glowGrad.addColorStop(1, "transparent");
|
||||
ctx.fillStyle = glowGrad;
|
||||
ctx.fill();
|
||||
|
||||
// Starlight pinpoint at center
|
||||
const starPulse = 0.6 + 0.4 * Math.sin(t * 0.3 + (i + j) * 0.2);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 1, 0, Math.PI * 2);
|
||||
ctx.fillStyle = `rgba(220, 230, 255, ${starPulse})`;
|
||||
ctx.fill();
|
||||
// Diamond spark at center
|
||||
ctx.save();
|
||||
ctx.translate(x, y);
|
||||
ctx.rotate(Math.PI / 4);
|
||||
const sparkSize = 1 + pulse;
|
||||
ctx.fillStyle = `rgba(180, 210, 255, ${pulse})`;
|
||||
ctx.fillRect(-sparkSize / 2, -sparkSize / 2, sparkSize, sparkSize);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -95,20 +84,17 @@ onMounted(() => {
|
||||
if (!ctx) return;
|
||||
|
||||
let t = 0;
|
||||
|
||||
const resize = () => {
|
||||
if (!canvas.value) return;
|
||||
canvas.value.width = window.innerWidth;
|
||||
canvas.value.height = window.innerHeight;
|
||||
};
|
||||
|
||||
const loop = () => {
|
||||
if (!canvas.value || !ctx) return;
|
||||
draw(ctx, canvas.value.width, canvas.value.height, t);
|
||||
t += 0.015;
|
||||
t += 0.01;
|
||||
animId = requestAnimationFrame(loop);
|
||||
};
|
||||
|
||||
resize();
|
||||
loop();
|
||||
window.addEventListener("resize", resize);
|
||||
@@ -124,9 +110,8 @@ onUnmounted(() => {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
background: #0c0e12;
|
||||
background: #090a0d;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
Reference in New Issue
Block a user