mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-11 14:06:45 +03:00
🔥 Added shader hero component
This commit is contained in:
@@ -9,16 +9,9 @@ export function Hero() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative min-h-[100vh] pt-20 pb-10 flex flex-col items-center justify-center px-4 sm:px-6 lg:px-8 overflow-hidden">
|
<section className="relative min-h-[100vh] pt-20 pb-10 flex flex-col items-center justify-center px-4 sm:px-6 lg:px-8 overflow-hidden">
|
||||||
{/* Elegant gradient background */}
|
|
||||||
<div className="absolute inset-0 -z-10 overflow-hidden">
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-accent/5"></div>
|
|
||||||
<div className="absolute -top-1/2 -left-1/2 w-full h-full bg-gradient-radial from-primary/10 to-transparent blur-3xl"></div>
|
|
||||||
<div className="absolute -bottom-1/2 -right-1/2 w-full h-full bg-gradient-radial from-accent/10 to-transparent blur-3xl"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* spline object */}
|
{/* spline object */}
|
||||||
<div className="spline-object absolute inset-0 max-lg:-z-10 max-h-[40rem] -translate-y-16 md:max-h-[50rem] lg:max-h-[60%] xl:max-h-[70%] 2xl:max-h-[80%] md:-translate-y-24 lg:-translate-y-28 flex items-center justify-center">
|
<div className="spline-object absolute inset-0 max-lg:-z-10 max-h-[40rem] -translate-y-16 md:max-h-[50rem] lg:max-h-[60%] xl:max-h-[70%] 2xl:max-h-[80%] md:-translate-y-24 lg:-translate-y-28 flex items-center justify-center">
|
||||||
<div className="absolute right-2 bottom-4 h-20 w-40 bg-[#f8fbfb] dark:bg-[#010708]"/>
|
<div className="absolute right-2 bottom-4 h-20 w-40 bg-background"/>
|
||||||
<Suspense fallback={
|
<Suspense fallback={
|
||||||
<div className="w-full h-full flex items-center justify-center">
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
<img
|
<img
|
||||||
@@ -44,13 +37,13 @@ export function Hero() {
|
|||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p className="mt-4 sm:mt-6 text-base sm:text-lg md:text-xl text-muted-foreground max-w-3xl mx-auto px-4">
|
<p className="mt-4 sm:mt-6 text-base sm:text-lg md:text-xl text-muted-foreground max-w-3xl mx-auto px-4 z-20">
|
||||||
Automatically mirror your GitHub repositories to self-hosted Gitea.
|
Automatically mirror your GitHub repositories to self-hosted Gitea.
|
||||||
Never lose access to your code with continuous backup and
|
Never lose access to your code with continuous backup and
|
||||||
synchronization.
|
synchronization.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="mt-6 sm:mt-8 flex flex-wrap items-center justify-center gap-3 text-xs sm:text-sm text-muted-foreground px-4">
|
<div className="mt-6 sm:mt-8 flex flex-wrap items-center justify-center gap-3 text-xs sm:text-sm text-muted-foreground px-4 z-20">
|
||||||
<div className="flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 text-primary">
|
<div className="flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 text-primary">
|
||||||
<Shield className="w-3 h-3 sm:w-4 sm:h-4" />
|
<Shield className="w-3 h-3 sm:w-4 sm:h-4" />
|
||||||
<span className="font-medium">Self-Hosted</span>
|
<span className="font-medium">Self-Hosted</span>
|
||||||
@@ -66,7 +59,7 @@ export function Hero() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Call to action buttons */}
|
{/* Call to action buttons */}
|
||||||
<div className="mt-8 sm:mt-10 flex flex-col sm:flex-row items-center justify-center gap-3 sm:gap-4 px-4">
|
<div className="mt-8 sm:mt-10 flex flex-col sm:flex-row items-center justify-center gap-3 sm:gap-4 px-4 z-20">
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
className="relative group w-full sm:w-auto min-h-[48px] text-base bg-gradient-to-r from-primary to-accent hover:from-primary/90 hover:to-accent/90 shadow-lg shadow-primary/25 hover:shadow-xl hover:shadow-primary/30 transition-all duration-300"
|
className="relative group w-full sm:w-auto min-h-[48px] text-base bg-gradient-to-r from-primary to-accent hover:from-primary/90 hover:to-accent/90 shadow-lg shadow-primary/25 hover:shadow-xl hover:shadow-primary/30 transition-all duration-300"
|
||||||
|
|||||||
140
www/src/components/ShaderBackground.astro
Normal file
140
www/src/components/ShaderBackground.astro
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
<canvas id="shader-canvas" class="hidden lg:block absolute inset-0 w-full h-full dark:opacity-90 z-10 pointer-events-none"></canvas>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById('shader-canvas') as HTMLCanvasElement | null;
|
||||||
|
if (!canvas) {
|
||||||
|
console.error('Canvas element not found');
|
||||||
|
} else {
|
||||||
|
const gl = canvas.getContext('webgl', { alpha: true });
|
||||||
|
|
||||||
|
if (!gl) {
|
||||||
|
console.error('WebGL not supported!');
|
||||||
|
} else {
|
||||||
|
const vertexShaderSource = `
|
||||||
|
attribute vec2 a_position;
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(a_position, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const fragmentShaderSource = `
|
||||||
|
precision mediump float;
|
||||||
|
uniform vec2 iResolution;
|
||||||
|
uniform float iTime;
|
||||||
|
uniform vec3 u_color1;
|
||||||
|
uniform vec3 u_color2;
|
||||||
|
#define iterations 2
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 uv = gl_FragCoord.xy / iResolution.xy;
|
||||||
|
vec2 mirrored_uv = uv;
|
||||||
|
|
||||||
|
if (mirrored_uv.x > 0.5) {
|
||||||
|
mirrored_uv.x = 1.0 - mirrored_uv.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float res = 1.0;
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
res += cos(mirrored_uv.y * 12.345 - iTime * 1.0 + cos(res * 12.234) * 0.2 + cos(mirrored_uv.x * 32.2345 + cos(mirrored_uv.y * 17.234))) + cos(mirrored_uv.x * 12.345);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 c = mix(u_color1, u_color2, cos(res + cos(mirrored_uv.y * 24.3214) * 0.1 + cos(mirrored_uv.x * 6.324 + iTime * 1.0) + iTime) * 0.5 + 0.5);
|
||||||
|
float vignette = clamp((length(mirrored_uv - 0.1 + cos(iTime * 0.9 + mirrored_uv.yx * 4.34 + mirrored_uv.xy * res) * 0.2) * 5.0 - 0.4), 0.0, 1.0);
|
||||||
|
vec3 final_color = mix(c, vec3(0.0), vignette);
|
||||||
|
gl_FragColor = vec4(final_color, length(final_color));
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
function createShader(context: WebGLRenderingContext, type: number, source: string): WebGLShader | null {
|
||||||
|
const shader = context.createShader(type);
|
||||||
|
if (!shader) return null;
|
||||||
|
|
||||||
|
context.shaderSource(shader, source);
|
||||||
|
context.compileShader(shader);
|
||||||
|
|
||||||
|
if (!context.getShaderParameter(shader, context.COMPILE_STATUS)) {
|
||||||
|
console.error('Shader compilation error:', context.getShaderInfoLog(shader));
|
||||||
|
context.deleteShader(shader);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
||||||
|
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
||||||
|
|
||||||
|
if (vertexShader && fragmentShader) {
|
||||||
|
const program = gl.createProgram();
|
||||||
|
if (program) {
|
||||||
|
gl.attachShader(program, vertexShader);
|
||||||
|
gl.attachShader(program, fragmentShader);
|
||||||
|
gl.linkProgram(program);
|
||||||
|
|
||||||
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||||
|
console.error('Program linking error:', gl.getProgramInfoLog(program));
|
||||||
|
} else {
|
||||||
|
gl.useProgram(program);
|
||||||
|
|
||||||
|
const positionBuffer = gl.createBuffer();
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||||
|
const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];
|
||||||
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
|
||||||
|
|
||||||
|
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
|
||||||
|
gl.enableVertexAttribArray(positionAttributeLocation);
|
||||||
|
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
|
||||||
|
|
||||||
|
const resolutionLocation = gl.getUniformLocation(program, "iResolution");
|
||||||
|
const timeLocation = gl.getUniformLocation(program, "iTime");
|
||||||
|
const color1Location = gl.getUniformLocation(program, "u_color1");
|
||||||
|
const color2Location = gl.getUniformLocation(program, "u_color2");
|
||||||
|
|
||||||
|
const color1 = [0.122, 0.502, 0.122]; // #1f801f
|
||||||
|
const color2 = [0.059, 0.251, 0.059]; // #0f400f
|
||||||
|
|
||||||
|
function render(time: number): void {
|
||||||
|
if (!gl || !program || !canvas) return;
|
||||||
|
|
||||||
|
time *= 0.001;
|
||||||
|
|
||||||
|
const displayWidth = canvas.clientWidth;
|
||||||
|
const displayHeight = canvas.clientHeight;
|
||||||
|
|
||||||
|
if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
|
||||||
|
canvas.width = displayWidth;
|
||||||
|
canvas.height = displayHeight;
|
||||||
|
gl.viewport(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.clearColor(0, 0, 0, 0);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
gl.useProgram(program);
|
||||||
|
|
||||||
|
if (resolutionLocation !== null) {
|
||||||
|
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
if (timeLocation !== null) {
|
||||||
|
gl.uniform1f(timeLocation, time);
|
||||||
|
}
|
||||||
|
if (color1Location !== null) {
|
||||||
|
gl.uniform3fv(color1Location, color1);
|
||||||
|
}
|
||||||
|
if (color2Location !== null) {
|
||||||
|
gl.uniform3fv(color2Location, color2);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
requestAnimationFrame(render);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(render);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
import '../styles/global.css';
|
import '../styles/global.css';
|
||||||
import { Header } from '../components/Header';
|
import { Header } from '../components/Header';
|
||||||
import { Hero } from '../components/Hero';
|
import { Hero } from '../components/Hero';
|
||||||
|
import ShaderBackground from '../components/ShaderBackground.astro';
|
||||||
import Features from '../components/Features.astro';
|
import Features from '../components/Features.astro';
|
||||||
import Screenshots from '../components/Screenshots.astro';
|
import Screenshots from '../components/Screenshots.astro';
|
||||||
import { Installation } from '../components/Installation';
|
import { Installation } from '../components/Installation';
|
||||||
@@ -117,7 +118,10 @@ const structuredData = {
|
|||||||
<Header client:load />
|
<Header client:load />
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<Hero client:load />
|
<div class="relative">
|
||||||
|
<ShaderBackground />
|
||||||
|
<Hero client:load />
|
||||||
|
</div>
|
||||||
<Features />
|
<Features />
|
||||||
<Screenshots />
|
<Screenshots />
|
||||||
<Installation client:load />
|
<Installation client:load />
|
||||||
|
|||||||
Reference in New Issue
Block a user