Initial commit: railwayka.ru landing page as dcape app
- Dcape app structure with Makefile, docker-compose.yml - Woodpecker CI/CD pipeline configuration - Custom Dockerfile with nginx alpine - Static website with dark theme and animations - Service cards, tech stack, GitOps workflow visualization - Konami code easter egg
This commit is contained in:
commit
90314a5851
|
|
@ -0,0 +1,2 @@
|
||||||
|
.env
|
||||||
|
.env.bak
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
# Woodpecker CI pipeline for railwayka landing page
|
||||||
|
|
||||||
|
variables:
|
||||||
|
- &dcape_img 'dcape-compose'
|
||||||
|
|
||||||
|
clone:
|
||||||
|
git:
|
||||||
|
image: woodpeckerci/plugin-git
|
||||||
|
settings:
|
||||||
|
lfs: false
|
||||||
|
tags: false
|
||||||
|
|
||||||
|
steps:
|
||||||
|
deploy:
|
||||||
|
image: *dcape_img
|
||||||
|
commands:
|
||||||
|
- make .default-deploy
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
ARG IMAGE=nginx
|
||||||
|
ARG IMAGE_VER=1.27-alpine
|
||||||
|
|
||||||
|
FROM --platform=$BUILDPLATFORM ${IMAGE}:${IMAGE_VER}
|
||||||
|
|
||||||
|
COPY html /usr/share/nginx/html
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
## dcape-app-railwayka-landing Makefile
|
||||||
|
## This file extends Makefile.app from dcape
|
||||||
|
#:
|
||||||
|
|
||||||
|
SHELL = /bin/bash
|
||||||
|
CFG ?= .env
|
||||||
|
CFG_BAK ?= $(CFG).bak
|
||||||
|
|
||||||
|
#- Docker repo & image name without version
|
||||||
|
IMAGE ?= nginx
|
||||||
|
|
||||||
|
#- ver
|
||||||
|
IMAGE_VER ?= 1.27-alpine
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# app custom config
|
||||||
|
|
||||||
|
# Overwrite for setup
|
||||||
|
APP_SITE ?= railwayka.ru
|
||||||
|
|
||||||
|
#- domain (no www for this site)
|
||||||
|
APP_ACME_DOMAIN ?= $(APP_SITE)
|
||||||
|
|
||||||
|
PERSIST_FILES =
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# if exists - load old values
|
||||||
|
-include $(CFG_BAK)
|
||||||
|
export
|
||||||
|
|
||||||
|
-include $(CFG)
|
||||||
|
export
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Find and include DCAPE_ROOT/Makefile
|
||||||
|
DCAPE_COMPOSE ?= dcape-compose
|
||||||
|
DCAPE_ROOT ?= $(shell docker inspect -f "{{.Config.Labels.dcape_root}}" $(DCAPE_COMPOSE))
|
||||||
|
|
||||||
|
ifeq ($(shell test -e $(DCAPE_ROOT)/Makefile.app && echo -n yes),yes)
|
||||||
|
include $(DCAPE_ROOT)/Makefile.app
|
||||||
|
else
|
||||||
|
include /opt/dcape/Makefile.app
|
||||||
|
endif
|
||||||
|
|
||||||
|
.default-deploy: docker-build
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
# railwayka.ru Landing Page
|
||||||
|
|
||||||
|
Business card website for railwayka.ru infrastructure, deployed via [dcape](https://github.com/dopos/dcape) GitOps platform.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Modern dark theme with animated stars background
|
||||||
|
- Service cards showcasing current and planned services
|
||||||
|
- Technology stack descriptions
|
||||||
|
- GitOps workflow visualization
|
||||||
|
- Konami code easter egg
|
||||||
|
- Responsive design
|
||||||
|
|
||||||
|
## Technology Stack
|
||||||
|
|
||||||
|
- **Nginx**: Alpine-based web server
|
||||||
|
- **Docker**: Containerized deployment
|
||||||
|
- **Traefik**: Automatic HTTPS via Let's Encrypt
|
||||||
|
- **Dcape**: GitOps-based deployment
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
This application uses GitOps workflow:
|
||||||
|
|
||||||
|
1. Push code to Git repository
|
||||||
|
2. Woodpecker CI automatically triggers
|
||||||
|
3. Application builds and deploys
|
||||||
|
4. Service goes live at https://railwayka.ru
|
||||||
|
|
||||||
|
### Manual Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone repository
|
||||||
|
git clone https://git.dc.railwayka.ru/howl/railwayka-landing.git
|
||||||
|
cd railwayka-landing
|
||||||
|
|
||||||
|
# Configure environment
|
||||||
|
make config
|
||||||
|
# Edit .env.sample and rename to .env
|
||||||
|
mv .env.sample .env
|
||||||
|
|
||||||
|
# Build and deploy
|
||||||
|
make docker-build
|
||||||
|
make up
|
||||||
|
```
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
To run locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Serve files with any web server
|
||||||
|
cd html
|
||||||
|
python3 -m http.server 8000
|
||||||
|
# Visit http://localhost:8000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── Makefile # Dcape app Makefile
|
||||||
|
├── docker-compose.yml # Service definition
|
||||||
|
├── Dockerfile # Custom nginx image
|
||||||
|
├── .woodpecker.yml # CI/CD pipeline
|
||||||
|
├── html/ # Static website files
|
||||||
|
│ ├── index.html
|
||||||
|
│ ├── style.css
|
||||||
|
│ └── script.js
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Railwayka Landing Page - dcape app config
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
labels:
|
||||||
|
- traefik.http.routers.${APP_TAG}.rule=Host(`${APP_SITE:?Must be set}`)
|
||||||
|
# TLS support
|
||||||
|
- traefik.http.routers.${APP_TAG}.tls.domains[0].main=${APP_SITE}
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
IMAGE: "${IMAGE}"
|
||||||
|
IMAGE_VER: "${IMAGE_VER}"
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>railwayka.ru - Infrastructure & Services</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="stars"></div>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<h1 class="glitch" data-text="railwayka.ru">railwayka.ru</h1>
|
||||||
|
<p class="tagline">Self-Hosted Infrastructure & Services</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="intro">
|
||||||
|
<p>Welcome to my personal infrastructure platform, powered by modern DevOps technologies and GitOps workflows.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="services">
|
||||||
|
<h2>Available Services</h2>
|
||||||
|
<div class="service-grid">
|
||||||
|
<div class="service-card">
|
||||||
|
<div class="service-icon">🔧</div>
|
||||||
|
<h3>Git Repository</h3>
|
||||||
|
<p>Self-hosted Git server with web interface</p>
|
||||||
|
<a href="https://git.dc.railwayka.ru" class="service-link">Visit Gitea →</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="service-card coming-soon">
|
||||||
|
<div class="service-icon">💬</div>
|
||||||
|
<h3>Matrix Server</h3>
|
||||||
|
<p>Decentralized, secure messaging</p>
|
||||||
|
<span class="badge">Coming Soon</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="service-card coming-soon">
|
||||||
|
<div class="service-icon">📝</div>
|
||||||
|
<h3>Blog</h3>
|
||||||
|
<p>Technical writing and documentation</p>
|
||||||
|
<span class="badge">Coming Soon</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="service-card coming-soon">
|
||||||
|
<div class="service-icon">🔐</div>
|
||||||
|
<h3>Password Manager</h3>
|
||||||
|
<p>Self-hosted credential storage</p>
|
||||||
|
<span class="badge">Coming Soon</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="service-card coming-soon">
|
||||||
|
<div class="service-icon">☁️</div>
|
||||||
|
<h3>Cloud Storage</h3>
|
||||||
|
<p>Private file storage and sync</p>
|
||||||
|
<span class="badge">Coming Soon</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="service-card coming-soon">
|
||||||
|
<div class="service-icon">📊</div>
|
||||||
|
<h3>Monitoring</h3>
|
||||||
|
<p>System metrics and dashboards</p>
|
||||||
|
<span class="badge">Coming Soon</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="tech-stack">
|
||||||
|
<h2>Technology Stack</h2>
|
||||||
|
<div class="tech-info">
|
||||||
|
<div class="tech-item">
|
||||||
|
<h3>🚀 Dcape</h3>
|
||||||
|
<p>GitOps-based infrastructure management platform. Deploy applications with simple <code>git push</code> commands.</p>
|
||||||
|
</div>
|
||||||
|
<div class="tech-item">
|
||||||
|
<h3>🐳 Docker</h3>
|
||||||
|
<p>All services run in isolated containers with automatic orchestration and health monitoring.</p>
|
||||||
|
</div>
|
||||||
|
<div class="tech-item">
|
||||||
|
<h3>🔒 Let's Encrypt</h3>
|
||||||
|
<p>Automatic SSL/TLS certificates with wildcard domain support for secure HTTPS connections.</p>
|
||||||
|
</div>
|
||||||
|
<div class="tech-item">
|
||||||
|
<h3>🌐 Traefik</h3>
|
||||||
|
<p>Modern reverse proxy with automatic service discovery and HTTPS routing.</p>
|
||||||
|
</div>
|
||||||
|
<div class="tech-item">
|
||||||
|
<h3>🗄️ PostgreSQL</h3>
|
||||||
|
<p>Shared production-grade database for application data persistence.</p>
|
||||||
|
</div>
|
||||||
|
<div class="tech-item">
|
||||||
|
<h3>📡 PowerDNS</h3>
|
||||||
|
<p>Self-hosted authoritative DNS server with API-driven zone management.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="about-gitops">
|
||||||
|
<h2>What is GitOps?</h2>
|
||||||
|
<p>GitOps is a modern infrastructure management approach where Git serves as the single source of truth. All infrastructure changes and application deployments are made through Git commits and pull requests.</p>
|
||||||
|
<div class="gitops-flow">
|
||||||
|
<div class="flow-step">
|
||||||
|
<span class="step-number">1</span>
|
||||||
|
<p>Push code to Git repository</p>
|
||||||
|
</div>
|
||||||
|
<div class="flow-arrow">→</div>
|
||||||
|
<div class="flow-step">
|
||||||
|
<span class="step-number">2</span>
|
||||||
|
<p>CI/CD pipeline builds</p>
|
||||||
|
</div>
|
||||||
|
<div class="flow-arrow">→</div>
|
||||||
|
<div class="flow-step">
|
||||||
|
<span class="step-number">3</span>
|
||||||
|
<p>Automatic deployment</p>
|
||||||
|
</div>
|
||||||
|
<div class="flow-arrow">→</div>
|
||||||
|
<div class="flow-step">
|
||||||
|
<span class="step-number">4</span>
|
||||||
|
<p>Service goes live</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>Powered by open-source technologies and self-hosted infrastructure</p>
|
||||||
|
<p class="footer-note">This server runs on <strong>Ubuntu 24.04</strong> with hardened SSH security (key-only authentication)</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
// Smooth scroll for any future internal links
|
||||||
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||||
|
anchor.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = document.querySelector(this.getAttribute('href'));
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'start'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add fade-in animation to cards on scroll
|
||||||
|
const observerOptions = {
|
||||||
|
threshold: 0.1,
|
||||||
|
rootMargin: '0px 0px -50px 0px'
|
||||||
|
};
|
||||||
|
|
||||||
|
const observer = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.style.opacity = '0';
|
||||||
|
entry.target.style.transform = 'translateY(20px)';
|
||||||
|
entry.target.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
entry.target.style.opacity = '1';
|
||||||
|
entry.target.style.transform = 'translateY(0)';
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
observer.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, observerOptions);
|
||||||
|
|
||||||
|
// Observe all service cards and tech items
|
||||||
|
document.querySelectorAll('.service-card, .tech-item, .flow-step').forEach(el => {
|
||||||
|
observer.observe(el);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Easter egg: Konami code detector
|
||||||
|
let konamiCode = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a'];
|
||||||
|
let konamiIndex = 0;
|
||||||
|
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === konamiCode[konamiIndex]) {
|
||||||
|
konamiIndex++;
|
||||||
|
if (konamiIndex === konamiCode.length) {
|
||||||
|
document.body.style.animation = 'rainbow 2s ease infinite';
|
||||||
|
setTimeout(() => {
|
||||||
|
document.body.style.animation = '';
|
||||||
|
konamiIndex = 0;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
konamiIndex = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add CSS for rainbow animation
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
@keyframes rainbow {
|
||||||
|
0% { filter: hue-rotate(0deg); }
|
||||||
|
100% { filter: hue-rotate(360deg); }
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
// Console message for developers
|
||||||
|
console.log('%c👋 Hello, developer!', 'font-size: 20px; color: #6366f1; font-weight: bold;');
|
||||||
|
console.log('%cInterested in the infrastructure? Check out https://git.dc.railwayka.ru', 'font-size: 14px; color: #a1a1aa;');
|
||||||
|
console.log('%cPowered by Dcape - GitOps infrastructure management', 'font-size: 12px; color: #6366f1;');
|
||||||
|
|
@ -0,0 +1,324 @@
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-primary: #0a0e27;
|
||||||
|
--bg-secondary: #141b3d;
|
||||||
|
--text-primary: #e4e4e7;
|
||||||
|
--text-secondary: #a1a1aa;
|
||||||
|
--accent: #6366f1;
|
||||||
|
--accent-hover: #4f46e5;
|
||||||
|
--card-bg: rgba(20, 27, 61, 0.6);
|
||||||
|
--border: rgba(99, 102, 241, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
line-height: 1.6;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stars {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
background-image:
|
||||||
|
radial-gradient(2px 2px at 20px 30px, white, transparent),
|
||||||
|
radial-gradient(2px 2px at 60px 70px, white, transparent),
|
||||||
|
radial-gradient(1px 1px at 50px 50px, white, transparent),
|
||||||
|
radial-gradient(1px 1px at 130px 80px, white, transparent),
|
||||||
|
radial-gradient(2px 2px at 90px 10px, white, transparent);
|
||||||
|
background-size: 200px 200px;
|
||||||
|
animation: twinkle 5s ease-in-out infinite;
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes twinkle {
|
||||||
|
0%, 100% { opacity: 0.4; }
|
||||||
|
50% { opacity: 0.7; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
text-align: center;
|
||||||
|
padding: 4rem 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: 800;
|
||||||
|
background: linear-gradient(135deg, var(--accent) 0%, #ec4899 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.glitch {
|
||||||
|
animation: glitch 3s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes glitch {
|
||||||
|
0%, 90%, 100% {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
92% {
|
||||||
|
text-shadow: 2px 2px #ff00de, -2px -2px #00fff9;
|
||||||
|
}
|
||||||
|
94% {
|
||||||
|
text-shadow: -2px 2px #ff00de, 2px -2px #00fff9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin: 4rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card {
|
||||||
|
background: var(--card-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(99, 102, 241, 0.1), transparent);
|
||||||
|
transition: left 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card:hover::before {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
border-color: var(--accent);
|
||||||
|
box-shadow: 0 10px 30px rgba(99, 102, 241, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card h3 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card p {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-link {
|
||||||
|
display: inline-block;
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-link:hover {
|
||||||
|
color: var(--accent-hover);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card.coming-soon {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
background: rgba(99, 102, 241, 0.2);
|
||||||
|
border: 1px solid var(--accent);
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-info {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-item {
|
||||||
|
background: var(--card-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-item h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-item p {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background: rgba(99, 102, 241, 0.2);
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-gitops {
|
||||||
|
background: var(--card-bg);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 3rem;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-gitops p {
|
||||||
|
text-align: center;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto 2rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gitops-flow {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-step {
|
||||||
|
background: rgba(99, 102, 241, 0.1);
|
||||||
|
border: 2px solid var(--accent);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 150px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-step:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
background: rgba(99, 102, 241, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-number {
|
||||||
|
display: block;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin: 0 auto 0.5rem;
|
||||||
|
background: var(--accent);
|
||||||
|
color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
line-height: 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-arrow {
|
||||||
|
color: var(--accent);
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem 0 2rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
margin-top: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-note {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer strong {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gitops-flow {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-arrow {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue