auto-save 2026-05-15 18:56 (~4)
This commit is contained in:
@@ -1,18 +1,5 @@
|
|||||||
{
|
{
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
|
||||||
"files_changed": 3,
|
|
||||||
"message": "Claude 会话活跃 · 最近命令:claude · 3 项未提交变更 · 最近提交:auto-save 2026-05-14 02:58 (~6)",
|
|
||||||
"ts": "2026-05-13T19:03:11Z",
|
|
||||||
"type": "session-heartbeat"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files_changed": 3,
|
|
||||||
"hash": "3df3ce4",
|
|
||||||
"message": "auto-save 2026-05-14 03:03 (~3)",
|
|
||||||
"ts": "2026-05-14T03:04:09+08:00",
|
|
||||||
"type": "commit"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"files_changed": 3,
|
"files_changed": 3,
|
||||||
"message": "Codex 会话活跃 · 最近命令:codex · 3 项未提交变更 · 最近提交:auto-save 2026-05-14 03:03 (~3)",
|
"message": "Codex 会话活跃 · 最近命令:codex · 3 项未提交变更 · 最近提交:auto-save 2026-05-14 03:03 (~3)",
|
||||||
@@ -3256,6 +3243,19 @@
|
|||||||
"message": "auto-save 2026-05-15 18:45 (~3)",
|
"message": "auto-save 2026-05-15 18:45 (~3)",
|
||||||
"hash": "d466f48",
|
"hash": "d466f48",
|
||||||
"files_changed": 3
|
"files_changed": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-05-15T18:51:34+08:00",
|
||||||
|
"type": "commit",
|
||||||
|
"message": "auto-save 2026-05-15 18:51 (~1)",
|
||||||
|
"hash": "7919e65",
|
||||||
|
"files_changed": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ts": "2026-05-15T10:54:49Z",
|
||||||
|
"type": "session-heartbeat",
|
||||||
|
"message": "Codex 会话活跃 · 最近命令:codex · 2 项未提交变更 · 最近提交:auto-save 2026-05-15 18:51 (~1)",
|
||||||
|
"files_changed": 2
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ export default function LoginPage() {
|
|||||||
<OasisCanvas />
|
<OasisCanvas />
|
||||||
<div className="login-oasis-shade" />
|
<div className="login-oasis-shade" />
|
||||||
<div className="relative z-10 mx-auto flex min-h-[calc(100vh-3rem)] w-full max-w-7xl items-center">
|
<div className="relative z-10 mx-auto flex min-h-[calc(100vh-3rem)] w-full max-w-7xl items-center">
|
||||||
<div className="grid w-full gap-5 lg:grid-cols-[minmax(0,1.16fr)_minmax(380px,440px)] lg:items-stretch">
|
<div className="grid w-full gap-5 lg:grid-cols-[minmax(0,1.28fr)_minmax(320px,380px)] lg:items-center">
|
||||||
<section className="login-hero login-oasis-hero order-2 relative min-h-[540px] overflow-hidden p-1 text-white sm:p-2 lg:order-1 lg:min-h-[660px]">
|
<section className="login-hero login-oasis-hero order-2 relative min-h-[540px] overflow-hidden p-1 text-white sm:p-2 lg:order-1 lg:min-h-[620px]">
|
||||||
<div className="relative z-10 flex h-full flex-col">
|
<div className="relative z-10 flex h-full flex-col">
|
||||||
<div className="flex flex-wrap items-center justify-between gap-4">
|
<div className="flex flex-wrap items-center justify-between gap-4">
|
||||||
<div className="login-wordmark">
|
<div className="login-wordmark">
|
||||||
@@ -140,10 +140,10 @@ export default function LoginPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="login-auth-panel order-1 flex min-h-[470px] items-center rounded-[8px] p-5 sm:p-8 lg:order-2 lg:min-h-[660px]">
|
<section className="login-auth-panel order-1 flex min-h-[390px] items-center rounded-[8px] p-5 sm:p-8 lg:order-2 lg:min-h-[460px]">
|
||||||
<form className="w-full" onSubmit={onSubmit}>
|
<form className="w-full" onSubmit={onSubmit}>
|
||||||
<div className="mb-8">
|
<div className="mb-6">
|
||||||
<div className="login-auth-icon mb-4 inline-flex h-12 w-12 items-center justify-center rounded-[8px] text-white">
|
<div className="login-auth-icon mb-4 inline-flex h-10 w-10 items-center justify-center rounded-[8px] text-white">
|
||||||
<LockKeyhole className="h-5 w-5" />
|
<LockKeyhole className="h-5 w-5" />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-2xl font-semibold text-white">身份验证</h2>
|
<h2 className="text-2xl font-semibold text-white">身份验证</h2>
|
||||||
|
|||||||
@@ -1,8 +1,38 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useRef } from "react"
|
||||||
|
|
||||||
export function OasisCanvas() {
|
export function OasisCanvas() {
|
||||||
|
const frameRef = useRef<HTMLIFrameElement | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const sendPointer = (type: "pointermove" | "pointerleave", event?: PointerEvent) => {
|
||||||
|
const frameWindow = frameRef.current?.contentWindow
|
||||||
|
if (!frameWindow) return
|
||||||
|
frameWindow.postMessage(
|
||||||
|
{
|
||||||
|
type: `skg-oasis-${type}`,
|
||||||
|
x: event?.clientX ?? 99999,
|
||||||
|
y: event?.clientY ?? 99999,
|
||||||
|
},
|
||||||
|
window.location.origin,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPointerMove = (event: PointerEvent) => sendPointer("pointermove", event)
|
||||||
|
const onPointerLeave = () => sendPointer("pointerleave")
|
||||||
|
|
||||||
|
window.addEventListener("pointermove", onPointerMove)
|
||||||
|
window.addEventListener("pointerleave", onPointerLeave)
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("pointermove", onPointerMove)
|
||||||
|
window.removeEventListener("pointerleave", onPointerLeave)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<iframe
|
<iframe
|
||||||
|
ref={frameRef}
|
||||||
allow="webgpu; fullscreen"
|
allow="webgpu; fullscreen"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className="login-oasis-canvas"
|
className="login-oasis-canvas"
|
||||||
|
|||||||
@@ -1380,16 +1380,29 @@
|
|||||||
const grassPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
const grassPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
|
||||||
const hitPoint = new THREE.Vector3();
|
const hitPoint = new THREE.Vector3();
|
||||||
|
|
||||||
window.addEventListener('mousemove', (e) => {
|
function applyPointerToGrass(clientX, clientY) {
|
||||||
mouseNDC.set((e.clientX / innerWidth) * 2 - 1, -(e.clientY / innerHeight) * 2 + 1);
|
mouseNDC.set((clientX / innerWidth) * 2 - 1, -(clientY / innerHeight) * 2 + 1);
|
||||||
raycaster.setFromCamera(mouseNDC, camera);
|
raycaster.setFromCamera(mouseNDC, camera);
|
||||||
if (raycaster.ray.intersectPlane(grassPlane, hitPoint)) {
|
if (raycaster.ray.intersectPlane(grassPlane, hitPoint)) {
|
||||||
mouseWorld.value.copy(hitPoint);
|
mouseWorld.value.copy(hitPoint);
|
||||||
// Compute distance from camera to mouse hit for auto-focus
|
// Compute distance from camera to mouse hit for auto-focus
|
||||||
mouseFocusDist = camera.position.distanceTo(hitPoint);
|
mouseFocusDist = camera.position.distanceTo(hitPoint);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('mousemove', (e) => {
|
||||||
|
applyPointerToGrass(e.clientX, e.clientY);
|
||||||
});
|
});
|
||||||
window.addEventListener('mouseleave', () => mouseWorld.value.set(99999, 0, 99999));
|
window.addEventListener('mouseleave', () => mouseWorld.value.set(99999, 0, 99999));
|
||||||
|
window.addEventListener('message', (event) => {
|
||||||
|
const data = event.data || {};
|
||||||
|
if (data.type === 'skg-oasis-pointermove') {
|
||||||
|
applyPointerToGrass(data.x, data.y);
|
||||||
|
}
|
||||||
|
if (data.type === 'skg-oasis-pointerleave') {
|
||||||
|
mouseWorld.value.set(99999, 0, 99999);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let resizeTimeout;
|
let resizeTimeout;
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user