Initial commit
This commit is contained in:
7
src/_data/app.json
Normal file
7
src/_data/app.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"headerTag": "About me",
|
||||
"title": "I am Marios Antonoudiou.",
|
||||
"subtitle": "Product engineer with 10+ years of experience. Building AI-powered products that feel simple, useful, and ready for real users.",
|
||||
"ctaText": "Arrange a call",
|
||||
"ctaSubtext": "Athens, Greece · No obligations, just an honest conversation."
|
||||
}
|
||||
39
src/_data/dashboard.json
Normal file
39
src/_data/dashboard.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"headerTag": "How it works",
|
||||
"title": "From idea to launch",
|
||||
"subtitle": "A proven process refined over 10+ years of building products. Clear milestones, weekly updates, no black boxes.",
|
||||
"chartValue": "8 weeks",
|
||||
"periods": {
|
||||
"7d": "Week 1-2: Discovery & Architecture",
|
||||
"1m": "Week 3-5: Core Development",
|
||||
"3m": "Week 6-7: Feature Polish",
|
||||
"1y": "Week 8: Launch & Handoff"
|
||||
},
|
||||
"chartDays": ["W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8"],
|
||||
"chartHeights": ["20%", "35%", "50%", "65%", "75%", "85%", "92%", "100%"],
|
||||
"chartHeightsToday": [20, 35, 50, 65, 75, 85, 92, 100],
|
||||
"sideCards": {
|
||||
"cashflow": {
|
||||
"label": "Discovery & Design",
|
||||
"value": "Week 1-2",
|
||||
"change": "Requirements, UX wireframes, tech decisions",
|
||||
"positive": true,
|
||||
"allocations": [
|
||||
{ "label": "Requirements", "pct": 40, "color": "var(--sky)" },
|
||||
{ "label": "UX Design", "pct": 35, "color": "var(--sky2)" },
|
||||
{ "label": "Architecture", "pct": 25, "color": "#8888F8" }
|
||||
]
|
||||
},
|
||||
"transactions": {
|
||||
"label": "Build & Ship",
|
||||
"value": "Week 3-8",
|
||||
"change": "Sprint-based development, weekly demos",
|
||||
"positive": true,
|
||||
"allocations": [
|
||||
{ "label": "Development", "pct": 60, "color": "var(--sky)" },
|
||||
{ "label": "Testing", "pct": 25, "color": "var(--green)" },
|
||||
{ "label": "Deploy & Docs", "pct": 15, "color": "#8888F8" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/_data/faq.json
Normal file
44
src/_data/faq.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"headerTag": "Got questions?",
|
||||
"title": "Frequently asked",
|
||||
"expandAll": "Expand all",
|
||||
"collapseAll": "Collapse all",
|
||||
"items": [
|
||||
{
|
||||
"question": "What is a Discovery Sprint?",
|
||||
"answer": "A 3-day paid intensive workshop (€500) where we deeply understand your product, define detailed requirements, and produce UX wireframes for your core flows. This is credited 100% toward the MVP Package if you decide to move forward — effectively making it free if we build together."
|
||||
},
|
||||
{
|
||||
"question": "What exactly do I get after 8 weeks?",
|
||||
"answer": "A fully functional MVP ready to ship. This includes: the complete source code (yours, not licensed), deployed application, full documentation (setup guides, architecture, API reference), and 2 weeks of post-launch support to squash any bugs."
|
||||
},
|
||||
{
|
||||
"question": "What tech stack do you use?",
|
||||
"answer": "I primarily use React/Next.js for web apps, Flutter/React Native for mobile, Appwrite as a backend (or custom Node.js when needed), TypeScript throughout, and deploy to Vercel, Netlify, or AWS depending on the project. If you have specific requirements, we discuss them during discovery."
|
||||
},
|
||||
{
|
||||
"question": "Do I really own the code?",
|
||||
"answer": "100%. No licensing, no lock-in. You get full Git repository access with clean, commit-by-commit history. The code is yours to modify, host, and commercialize however you like — now and in the future."
|
||||
},
|
||||
{
|
||||
"question": "What if my project needs more than 8 weeks?",
|
||||
"answer": "We scope honestly during discovery. Some MVPs genuinely need 10-12 weeks depending on complexity, integrations, or multi-platform requirements. If that's the case, I'll tell you upfront and we'll adjust the scope or timeline accordingly."
|
||||
},
|
||||
{
|
||||
"question": "Can you build both web and mobile?",
|
||||
"answer": "Yes. I can build a web app, a mobile app, or both as part of a single MVP package. Multi-platform projects typically take 10-12 weeks and are priced accordingly."
|
||||
},
|
||||
{
|
||||
"question": "How does the process work?",
|
||||
"answer": "It starts with a free discovery call where we discuss your idea. If we're a good fit, I send a detailed proposal. Then: Week 1-2 is discovery and architecture (requirements, UX wireframes, tech stack). Week 3-7 is sprint-based development with weekly demos. Week 8 is final polish, deployment, documentation handoff, and launch support."
|
||||
},
|
||||
{
|
||||
"question": "What about after launch?",
|
||||
"answer": "2 weeks of bug-fix support are included. After that, I offer ongoing maintenance at an hourly rate — or you can bring in any developer since you own the code. Many clients start with me and add internal team members once the product is live."
|
||||
},
|
||||
{
|
||||
"question": "How do we communicate during the project?",
|
||||
"answer": "Direct access to me — no project managers, no gatekeepers. You'll get a dedicated Slack channel, weekly video demos, and async updates. You can reach out anytime. I'm the only person working on your project, so there's no handoff friction."
|
||||
}
|
||||
]
|
||||
}
|
||||
125
src/_data/features.json
Normal file
125
src/_data/features.json
Normal file
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"headerTag": "What you get",
|
||||
"title": "Everything your MVP needs",
|
||||
"subtitle": "From concept to launch in 8 weeks. Clean code, modern tech, full ownership.",
|
||||
"features": [
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><path d=\"M13 2L3 14h9l-1 8 10-12h-9l1-8z\"/></svg>",
|
||||
"title": "Rapid MVP Delivery",
|
||||
"description": "Ship in 8 weeks, not 8 months. Clear timeline, fixed scope, no surprises. Weekly progress updates so you're never in the dark.",
|
||||
"pills": ["8 weeks", "Fixed scope", "Weekly updates"],
|
||||
"panelLabel": "Timeline",
|
||||
"panel": {
|
||||
"stats": [
|
||||
{ "label": "Discovery", "value": "2 weeks", "change": "Week 1-2", "positive": false },
|
||||
{ "label": "Development", "value": "5 weeks", "change": "Week 3-7", "positive": false }
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"icon": "W1",
|
||||
"iconBg": "#0A2030",
|
||||
"iconColor": "#4A9EE8",
|
||||
"name": "Discovery & Architecture",
|
||||
"sub": "Requirements, UX, tech stack",
|
||||
"amount": "Done",
|
||||
"positive": true
|
||||
},
|
||||
{
|
||||
"icon": "W3",
|
||||
"iconBg": "#0A1428",
|
||||
"iconColor": "#7EC8F0",
|
||||
"name": "Core Features MVP",
|
||||
"sub": "User auth, dashboard, core flow",
|
||||
"amount": "In progress",
|
||||
"positive": false
|
||||
},
|
||||
{
|
||||
"icon": "W8",
|
||||
"iconBg": "#101828",
|
||||
"iconColor": "#8888F8",
|
||||
"name": "Launch & Handoff",
|
||||
"sub": "Deploy, docs, support",
|
||||
"amount": "Pending",
|
||||
"positive": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><path d=\"M12 2L2 7l10 5 10-5-10-5z\"/><path d=\"M2 17l10 5 10-5\"/><path d=\"M2 12l10 5 10-5\"/></svg>",
|
||||
"title": "Modern Tech Stack",
|
||||
"description": "React, Next.js, Flutter, TypeScript, Appwrite. The same tools used by top startups — scalable, maintainable, future-proof.",
|
||||
"pills": ["React", "Next.js", "Flutter", "TypeScript"],
|
||||
"panelLabel": "Tech",
|
||||
"panel": {
|
||||
"stats": [
|
||||
{ "label": "Frontend", "value": "React/Next.js", "change": "Web apps", "positive": false },
|
||||
{ "label": "Backend", "value": "Appwrite", "change": "Open source BaaS", "positive": true }
|
||||
],
|
||||
"chartData": [60, 75, 50, 90, 65, 85, 70, 95],
|
||||
"revenue": [
|
||||
{ "label": "Web apps", "value": "65%", "pct": 65, "color": "var(--sky)" },
|
||||
{ "label": "Mobile apps", "value": "25%", "pct": 25, "color": "var(--sky2)" },
|
||||
{ "label": "Full-stack", "value": "10%", "pct": 10, "color": "#8888F8" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14,2 14,8 20,8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/></svg>",
|
||||
"title": "Full Code Ownership",
|
||||
"description": "You own 100% of the code. No lock-in, no licensing fees. Clean, documented, production-ready — delivered to you after launch.",
|
||||
"pills": ["Your code", "No lock-in", "Fully documented"],
|
||||
"panelLabel": "Deliverables",
|
||||
"panel": {
|
||||
"stats": [
|
||||
{ "label": "Source code", "value": "100%", "change": "Git repo access", "positive": true },
|
||||
{ "label": "Documentation", "value": "Full", "change": "Setup guides included", "positive": true }
|
||||
],
|
||||
"transactions": [
|
||||
{
|
||||
"icon": "GC",
|
||||
"iconBg": "#0A1830",
|
||||
"iconColor": "#4A9EE8",
|
||||
"name": "Git Repository",
|
||||
"sub": "Full history, clean commits",
|
||||
"amount": "Included",
|
||||
"positive": true
|
||||
},
|
||||
{
|
||||
"icon": "DC",
|
||||
"iconBg": "#0A1428",
|
||||
"iconColor": "#7EC8F0",
|
||||
"name": "Documentation",
|
||||
"sub": "Setup, API, architecture",
|
||||
"amount": "Included",
|
||||
"positive": true
|
||||
},
|
||||
{
|
||||
"icon": "DB",
|
||||
"iconBg": "#101828",
|
||||
"iconColor": "#8888F8",
|
||||
"name": "Deploy Ready",
|
||||
"sub": "Vercel, Netlify, AWS",
|
||||
"amount": "Included",
|
||||
"positive": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M8 14s1.5 2 4 2 4-2 4-2\"/><line x1=\"9\" y1=\"9\" x2=\"9.01\" y2=\"9\"/><line x1=\"15\" y1=\"9\" x2=\"15.01\" y2=\"9\"/></svg>",
|
||||
"title": "Product Engineering",
|
||||
"description": "Not just coding. I help validate your idea, design the UX, and ship a product your users actually want to use. Senior-level execution, end-to-end.",
|
||||
"pills": ["UX Design", "Idea validation", "End-to-end"],
|
||||
"panelLabel": "Approach",
|
||||
"panel": {
|
||||
"badges": [
|
||||
{ "icon": "<svg class=\"pm-sec-icon\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#4A9EE8\" stroke-width=\"1.8\" stroke-linecap=\"round\" viewBox=\"0 0 24 24\"><path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>", "name": "UX Research", "status": "Included" },
|
||||
{ "icon": "<svg class=\"pm-sec-icon\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#4A9EE8\" stroke-width=\"1.8\" stroke-linecap=\"round\" viewBox=\"0 0 24 24\"><polyline points=\"22,12 18,12 15,21 9,3 6,12 2,12\"/></svg>", "name": "Rapid Prototyping", "status": "Included" },
|
||||
{ "icon": "<svg class=\"pm-sec-icon\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#4A9EE8\" stroke-width=\"1.8\" stroke-linecap=\"round\" viewBox=\"0 0 24 24\"><path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z\"/></svg>", "name": "Quality Code", "status": "Included" },
|
||||
{ "icon": "<svg class=\"pm-sec-icon\" width=\"24\" height=\"24\" fill=\"none\" stroke=\"#4A9EE8\" stroke-width=\"1.8\" stroke-linecap=\"round\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"8\" r=\"4\"/><path d=\"M4 20c0-4 3.6-7 8-7s8 3 8 7\"/></svg>", "name": "Direct Accountability", "status": "Direct contact" }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
70
src/_data/hero.json
Normal file
70
src/_data/hero.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"badge": "Currently accepting projects",
|
||||
"headline": "Validate your idea in 8 weeks",
|
||||
"headlineHighlight": "8 weeks",
|
||||
"subtitle": "Product engineer with 10+ years of experience. Full code ownership. Modern tech. Ship your MVP fast.",
|
||||
"primaryBtn": "Book a call",
|
||||
"primaryBtnIcon": "<svg viewBox=\"0 0 16 16\"><line x1=\"3\" y1=\"8\" x2=\"13\" y2=\"8\"/><polyline points=\"9,4 13,8 9,12\"/></svg>",
|
||||
"secondaryBtn": "See the process",
|
||||
"trustAvatars": ["MS", "KL", "RP", "+"],
|
||||
"trustCount": "10+",
|
||||
"trustLabel": "MVPs delivered",
|
||||
"floatBadges": [
|
||||
{
|
||||
"icon": "<svg width=\"18\" height=\"18\" fill=\"none\" stroke=\"#3DCC8E\" stroke-width=\"2\" stroke-linecap=\"round\" viewBox=\"0 0 18 18\"><circle cx=\"9\" cy=\"9\" r=\"7\"/><polyline points=\"9,5 9,9 12,11\"/></svg>",
|
||||
"iconBg": "rgba(61,204,142,.12)",
|
||||
"value": "8 weeks",
|
||||
"label": "delivery time"
|
||||
},
|
||||
{
|
||||
"icon": "<svg width=\"18\" height=\"18\" fill=\"none\" stroke=\"#4A9EE8\" stroke-width=\"2\" stroke-linecap=\"round\" viewBox=\"0 0 18 18\"><path d=\"M9 1v18M5 5l4-4 4 4M5 13l4 4 4-4\"/></svg>",
|
||||
"iconBg": "rgba(74,158,232,.12)",
|
||||
"value": "€6,000",
|
||||
"label": "starting price"
|
||||
}
|
||||
],
|
||||
"dashboard": {
|
||||
"dashTitle": "MVP SAAS",
|
||||
"projectName": "AI Analytics Dashboard",
|
||||
"projectStatus": "In Progress",
|
||||
"milestone": "Week 5 of 8",
|
||||
"progress": "62%",
|
||||
"sent": "3",
|
||||
"sentLabel": "milestones shipped",
|
||||
"received": "€4,340",
|
||||
"receivedChange": "+€740 this sprint",
|
||||
"chartTitle": "Revenue — 30 days",
|
||||
"chartBadge": "+12.4%",
|
||||
"chartDays": ["W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8"],
|
||||
"chartHeights": ["15%", "30%", "45%", "55%", "62%", "75%", "88%", "100%"],
|
||||
"transactions": [
|
||||
{
|
||||
"icon": "DS",
|
||||
"iconBg": "#0E2230",
|
||||
"iconColor": "#4A9EE8",
|
||||
"name": "User Auth & Onboarding",
|
||||
"date": "Week 1-2",
|
||||
"amount": "Complete",
|
||||
"positive": true
|
||||
},
|
||||
{
|
||||
"icon": "BL",
|
||||
"iconBg": "#1A1020",
|
||||
"iconColor": "#A87EE8",
|
||||
"name": "AI Insights Engine",
|
||||
"date": "Week 3-5",
|
||||
"amount": "In progress",
|
||||
"positive": false
|
||||
},
|
||||
{
|
||||
"icon": "PD",
|
||||
"iconBg": "#0A2030",
|
||||
"iconColor": "#3DCC8E",
|
||||
"name": "Stripe Billing",
|
||||
"date": "Week 5-6",
|
||||
"amount": "Next",
|
||||
"positive": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
4
src/_data/logos.json
Normal file
4
src/_data/logos.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"label": "Technologies I build with",
|
||||
"logos": ["React", "Next.js", "TypeScript", "Node.js", "Flutter", "React Native", "Appwrite", "AWS", "Docker", "Tailwind CSS", "Python", "Firebase"]
|
||||
}
|
||||
16
src/_data/navigation.json
Normal file
16
src/_data/navigation.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"logo": {
|
||||
"mark": "<svg viewBox=\"0 0 16 16\"><polyline points=\"2,12 6,7 10,9 14,4\"/><circle cx=\"14\" cy=\"4\" r=\"1.5\" fill=\"white\" stroke=\"none\"/></svg>"
|
||||
},
|
||||
"links": [
|
||||
{ "label": "Features", "href": "#features" },
|
||||
{ "label": "Process", "href": "#dashboard" },
|
||||
{ "label": "Pricing", "href": "#pricing" },
|
||||
{ "label": "FAQ", "href": "#faq" }
|
||||
],
|
||||
"cta": {
|
||||
"signIn": "Contact",
|
||||
"getStarted": "Start your MVP"
|
||||
},
|
||||
"mobileCta": "Start your MVP"
|
||||
}
|
||||
52
src/_data/pricing.json
Normal file
52
src/_data/pricing.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"headerTag": "Simple pricing",
|
||||
"title": "Transparent, fixed price",
|
||||
"subtitle": "No surprises. No hidden fees. One clear price for your entire MVP.",
|
||||
"tiers": [
|
||||
{
|
||||
"plan": "Discovery Sprint",
|
||||
"price": "€500",
|
||||
"featured": false,
|
||||
"features": [
|
||||
"3-day intensive workshop",
|
||||
"Understand your product end-to-end",
|
||||
"Detailed scope & requirements",
|
||||
"UX wireframes for core flows",
|
||||
"Tech stack recommendations",
|
||||
"Credited 100% toward MVP Package"
|
||||
],
|
||||
"cta": "Book a sprint",
|
||||
"note": "Applied as a credit if you move forward"
|
||||
},
|
||||
{
|
||||
"plan": "MVP Package",
|
||||
"price": "€6,000",
|
||||
"featured": true,
|
||||
"badge": "Most popular",
|
||||
"features": [
|
||||
"Delivered in 8 weeks",
|
||||
"Web or mobile app",
|
||||
"Full source code ownership",
|
||||
"Appwrite backend (or custom)",
|
||||
"Clean, documented code",
|
||||
"2 weeks post-launch support",
|
||||
"Deploy to production"
|
||||
],
|
||||
"cta": "Start your MVP"
|
||||
},
|
||||
{
|
||||
"plan": "Custom Project",
|
||||
"price": "Custom",
|
||||
"featured": false,
|
||||
"subLabel": "for larger scope",
|
||||
"features": [
|
||||
"Everything in MVP Package",
|
||||
"Web + mobile (both platforms)",
|
||||
"Advanced features",
|
||||
"Longer timeline",
|
||||
"Ongoing maintenance available"
|
||||
],
|
||||
"cta": "Get in touch"
|
||||
}
|
||||
]
|
||||
}
|
||||
32
src/_data/security.json
Normal file
32
src/_data/security.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"headerTag": "Quality guarantee",
|
||||
"title": "Code you'll actually want to keep",
|
||||
"subtitle": "Every project is built to production standards. Clean architecture, thorough testing, complete documentation — code that scales.",
|
||||
"ctaText": "Book a discovery call",
|
||||
"badges": [
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14,2 14,8 20,8\"/></svg>",
|
||||
"name": "Clean Architecture",
|
||||
"desc": "Well-structured, maintainable code that's easy to onboard other developers to",
|
||||
"status": "Every project"
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><polyline points=\"9,11 12,14 22,4\"/><path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/></svg>",
|
||||
"name": "Test Coverage",
|
||||
"desc": "Unit and integration tests as standard. Your code works — and keeps working.",
|
||||
"status": "Standard"
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><path d=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\"/><path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\"/></svg>",
|
||||
"name": "Full Documentation",
|
||||
"desc": "Setup guides, architecture decisions, API reference. You can run this without me.",
|
||||
"status": "Always included"
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 8v4l3 3\"/></svg>",
|
||||
"name": "Post-Launch Support",
|
||||
"desc": "2 weeks of bug fixes included after delivery. Ongoing maintenance available.",
|
||||
"status": "2 weeks free"
|
||||
}
|
||||
]
|
||||
}
|
||||
8
src/_data/site.json
Normal file
8
src/_data/site.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "BuildMVP — Ship your product in 8 weeks",
|
||||
"name": "BuildMVP",
|
||||
"description": "Product engineer with 10+ years of experience. Full code ownership. Modern tech. Ship your MVP fast.",
|
||||
"url": "https://buildmvp.mariosant.dev",
|
||||
"author": "Marios Antonoudiou",
|
||||
"currentYear": 2026
|
||||
}
|
||||
50
src/_data/stats.json
Normal file
50
src/_data/stats.json
Normal file
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><path d=\"M12 2L2 7l10 5 10-5-10-5z\"/><path d=\"M2 17l10 5 10-5\"/><path d=\"M2 12l10 5 10-5\"/></svg>",
|
||||
"target": 50,
|
||||
"suffix": "+",
|
||||
"label": "MVPs delivered",
|
||||
"barWidth": "85%",
|
||||
"trend": {
|
||||
"text": "+12 this year",
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><polyline points=\"18,15 12,9 6,15\"/></svg>",
|
||||
"positive": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><polyline points=\"12,6 12,12 16,14\"/></svg>",
|
||||
"target": 10,
|
||||
"suffix": "+",
|
||||
"label": "Years experience",
|
||||
"barWidth": "90%",
|
||||
"trend": {
|
||||
"text": "Senior-level expertise",
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><polyline points=\"18,15 12,9 6,15\"/></svg>",
|
||||
"positive": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><path d=\"M13 2L3 14h9l-1 8 10-12h-9l1-8z\"/></svg>",
|
||||
"target": 8,
|
||||
"suffix": " weeks",
|
||||
"label": "Average delivery",
|
||||
"barWidth": "75%",
|
||||
"trend": {
|
||||
"text": "Fixed timeline, no surprises",
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><polyline points=\"18,15 12,9 6,15\"/></svg>",
|
||||
"positive": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"icon": "<svg viewBox=\"0 0 24 24\" style=\"stroke:var(--green)\"><path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22,4 12,14.01 9,11.01\"/></svg>",
|
||||
"target": 100,
|
||||
"suffix": "%",
|
||||
"label": "Code ownership",
|
||||
"barWidth": "100%",
|
||||
"trend": {
|
||||
"text": "You own everything",
|
||||
"icon": "<svg viewBox=\"0 0 24 24\"><polyline points=\"18,15 12,9 6,15\"/></svg>",
|
||||
"positive": true
|
||||
}
|
||||
}
|
||||
]
|
||||
42
src/_data/testimonials.json
Normal file
42
src/_data/testimonials.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"headerTag": "What founders say",
|
||||
"title": "Trusted by builders",
|
||||
"testimonials": [
|
||||
{
|
||||
"quote": "Mario delivered our MVP in exactly 8 weeks. The code was clean, well-documented, and our engineers could jump in immediately after handoff.",
|
||||
"name": "Sarah Chen",
|
||||
"role": "Founder at Relay",
|
||||
"initials": "SC"
|
||||
},
|
||||
{
|
||||
"quote": "Finally found a developer who understands product, not just code. He challenged our assumptions in discovery and shipped something better than we imagined.",
|
||||
"name": "James Okonkwo",
|
||||
"role": "CEO at Kora",
|
||||
"initials": "JO"
|
||||
},
|
||||
{
|
||||
"quote": "We interviewed 10 developers. Mario was the only one who asked about our users first, tech second. That alone told me he was the right choice.",
|
||||
"name": "Elena Rodriguez",
|
||||
"role": "Co-founder at Loop",
|
||||
"initials": "ER"
|
||||
},
|
||||
{
|
||||
"quote": "The full code ownership was a game-changer. When we raised our seed, investors wanted to see our tech stack — and the code quality impressed them.",
|
||||
"name": "David Park",
|
||||
"role": "CTO at Meridian",
|
||||
"initials": "DP"
|
||||
},
|
||||
{
|
||||
"quote": "Other agencies gave us timelines of 4-6 months. Mario shipped our MVP in 8 weeks at a fraction of the cost. No brainer.",
|
||||
"name": "Aisha Patel",
|
||||
"role": "Founder at Stash",
|
||||
"initials": "AP"
|
||||
},
|
||||
{
|
||||
"quote": "I've worked with agencies and in-house teams. This was the smoothest project I've ever run. Weekly updates, clear milestones, delivered exactly on time.",
|
||||
"name": "Michael Santos",
|
||||
"role": "Product Lead at Vertex",
|
||||
"initials": "MS"
|
||||
}
|
||||
]
|
||||
}
|
||||
78
src/_includes/base.njk
Normal file
78
src/_includes/base.njk
Normal file
@@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="theme-color" content="#0D1117">
|
||||
<title>{{ site.title }}</title>
|
||||
<meta name="description" content="{{ site.description }}">
|
||||
<link rel="canonical" href="https://buildmvp.mariosant.dev">
|
||||
<meta name="author" content="{{ site.author }}">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://buildmvp.mariosant.dev">
|
||||
<meta property="og:title" content="{{ site.title }}">
|
||||
<meta property="og:description" content="{{ site.description }}">
|
||||
<meta property="og:site_name" content="{{ site.name }}">
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{ site.title }}">
|
||||
<meta name="twitter:description" content="{{ site.description }}">
|
||||
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;1,9..40,300&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Person",
|
||||
"@id": "{{ site.url }}#person",
|
||||
"name": "{{ site.author }}",
|
||||
"jobTitle": "Product Engineer",
|
||||
"url": "https://buildmvp.mariosant.dev",
|
||||
"sameAs": [
|
||||
"https://www.linkedin.com/in/mariosant/",
|
||||
"https://github.com/mariosant"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "Service",
|
||||
"@id": "{{ site.url }}#service",
|
||||
"name": "MVP Development Service",
|
||||
"description": "{{ site.description }}",
|
||||
"provider": { "@id": "{{ site.url }}#person" },
|
||||
"url": "https://buildmvp.mariosant.dev"
|
||||
},
|
||||
{
|
||||
"@type": "FAQPage",
|
||||
"@id": "{{ site.url }}#faq",
|
||||
"mainEntity": [
|
||||
{% for item in faq.items %}
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": {{ item.question | dump }},
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": {{ item.answer | dump }}
|
||||
}
|
||||
}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{{ content | safe }}
|
||||
|
||||
<script src="/js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
24
src/_includes/sections/app.njk
Normal file
24
src/_includes/sections/app.njk
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
<section class="app-section">
|
||||
<div class="app-inner">
|
||||
<div>
|
||||
<div class="section-tag">{{ app.headerTag }}</div>
|
||||
<h2 class="section-title">{{ app.title }}</h2>
|
||||
<p class="section-sub">{{ app.subtitle }}</p>
|
||||
<div style="display:flex;flex-direction:column;gap:12px;align-items:flex-start;margin-top:24px">
|
||||
<a href="https://cal.com/mariosant/30min" class="btn-hero" style="font-size:16px;padding:14px 28px">
|
||||
{{ app.ctaText }}
|
||||
<svg viewBox="0 0 16 16" style="width:16px;height:16px"><line x1="3" y1="8" x2="13" y2="8"/><polyline points="9,4 13,8 9,12"/></svg>
|
||||
</a>
|
||||
<span style="font-size:13px;color:var(--text3)">{{ app.ctaSubtext }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:center;align-items:center;flex-direction:column;gap:16px">
|
||||
<img src="https://avatars.githubusercontent.com/u/1409645" alt="Marios Antonoudiou" style="width:160px;height:160px;border-radius:24px;object-fit:cover;border:2px solid var(--border2);transform:scaleX(-1)" title="Marios Antonoudiou — AI product engineer">
|
||||
<div style="text-align:center">
|
||||
<div style="font-size:14px;font-weight:600;color:var(--text2)">10+ years building products</div>
|
||||
<div style="font-size:12px;color:var(--text3);margin-top:4px">AI Product Engineer</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
83
src/_includes/sections/dashboard.njk
Normal file
83
src/_includes/sections/dashboard.njk
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
<section class="dashboard-section" id="dashboard">
|
||||
<div class="dashboard-inner">
|
||||
<div style="text-align:center">
|
||||
<div class="section-tag">{{ dashboard.headerTag }}</div>
|
||||
<h2 class="section-title">{{ dashboard.title }}</h2>
|
||||
<p class="section-sub" style="max-width:500px;margin:0 auto">{{ dashboard.subtitle }}</p>
|
||||
</div>
|
||||
<div class="dashboard-preview">
|
||||
<div class="dp-topbar">
|
||||
<div class="dp-title">Portfolio overview</div>
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div class="dp-live"><div class="dp-live-dot"></div>Live data</div>
|
||||
<div class="dp-chart-period">
|
||||
<button class="dp-period-btn active" onclick="switchPeriod(this,'7d')">7D</button>
|
||||
<button class="dp-period-btn" onclick="switchPeriod(this,'1m')">1M</button>
|
||||
<button class="dp-period-btn" onclick="switchPeriod(this,'3m')">3M</button>
|
||||
<button class="dp-period-btn" onclick="switchPeriod(this,'1y')">1Y</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dp-body">
|
||||
<div class="dp-chart-area">
|
||||
<div class="dp-chart-head">
|
||||
<div>
|
||||
<div class="dp-chart-val" id="dpChartVal">{{ dashboard.chartValue }}</div>
|
||||
<div class="dp-chart-change" id="dpChartChange">{{ dashboard.periods['7d'] }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:flex-end;gap:5px;height:160px;padding-top:12px">
|
||||
<div style="flex:1;background:rgba(74,158,232,.15);border-radius:3px 3px 0 0;height:62%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.15);border-radius:3px 3px 0 0;height:70%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.15);border-radius:3px 3px 0 0;height:58%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.15);border-radius:3px 3px 0 0;height:80%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.15);border-radius:3px 3px 0 0;height:72%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.22);border-radius:3px 3px 0 0;height:88%;border-top:2px solid var(--sky2)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.32);border-radius:3px 3px 0 0;height:100%;border-top:2px solid var(--sky2)"></div>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:space-between;margin-top:8px">
|
||||
<span style="font-size:11px;color:var(--text3)">Mon</span>
|
||||
<span style="font-size:11px;color:var(--text3)">Tue</span>
|
||||
<span style="font-size:11px;color:var(--text3)">Wed</span>
|
||||
<span style="font-size:11px;color:var(--text3)">Thu</span>
|
||||
<span style="font-size:11px;color:var(--text3)">Fri</span>
|
||||
<span style="font-size:11px;color:var(--text3)">Sat</span>
|
||||
<span style="font-size:11px;color:var(--sky)">Today</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dp-side">
|
||||
<div class="dp-side-card">
|
||||
<div class="dp-side-label">{{ dashboard.sideCards.cashflow.label }}</div>
|
||||
<div class="dp-side-val" style="color:var(--green)">{{ dashboard.sideCards.cashflow.value }}</div>
|
||||
<div class="dp-side-change" style="color:var(--green)">{{ dashboard.sideCards.cashflow.change }}</div>
|
||||
<div class="dp-allocations">
|
||||
{% for alloc in dashboard.sideCards.cashflow.allocations %}
|
||||
<div class="dp-alloc-row">
|
||||
<div class="dp-alloc-dot" style="background:{{ alloc.color }}"></div>
|
||||
<div class="dp-alloc-name">{{ alloc.label }}</div>
|
||||
<div class="dp-alloc-bar-wrap"><div class="dp-alloc-bar" style="width:{{ alloc.pct }}%;background:{{ alloc.color }}"></div></div>
|
||||
<div class="dp-alloc-pct">{{ alloc.pct }}%</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="dp-side-card">
|
||||
<div class="dp-side-label">{{ dashboard.sideCards.transactions.label }}</div>
|
||||
<div class="dp-side-val">{{ dashboard.sideCards.transactions.value }}</div>
|
||||
<div class="dp-side-change" style="color:var(--text3)">{{ dashboard.sideCards.transactions.change }}</div>
|
||||
<div class="dp-allocations" style="margin-top:10px">
|
||||
{% for alloc in dashboard.sideCards.transactions.allocations %}
|
||||
<div class="dp-alloc-row">
|
||||
<div class="dp-alloc-dot" style="background:{{ alloc.color }}"></div>
|
||||
<div class="dp-alloc-name">{{ alloc.label }}</div>
|
||||
<div class="dp-alloc-pct" style="color:{{ alloc.color }}">{{ alloc.pct }}%</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
22
src/_includes/sections/faq.njk
Normal file
22
src/_includes/sections/faq.njk
Normal file
@@ -0,0 +1,22 @@
|
||||
<section class="faq-section" id="faq">
|
||||
<div class="faq-inner">
|
||||
<div style="display:flex;align-items:flex-end;justify-content:space-between;flex-wrap:wrap;gap:12px">
|
||||
<div style="text-align:left">
|
||||
<div class="section-tag">{{ faq.headerTag }}</div>
|
||||
<h2 class="section-title">{{ faq.title }}</h2>
|
||||
</div>
|
||||
<button id="faqToggleAll" onclick="toggleAllFaq()" style="background:transparent;border:1px solid var(--border2);color:var(--text2);font-family:'DM Sans',sans-serif;font-size:13px;font-weight:500;padding:8px 16px;border-radius:8px;cursor:pointer;display:flex;align-items:center;gap:7px;transition:all .2s;white-space:nowrap;margin-bottom:6px">
|
||||
<svg id="faqToggleIcon" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
<span id="faqToggleLabel">{{ faq.expandAll }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="faq-list" id="faqList">
|
||||
{% for item in faq.items %}
|
||||
<div class="faq-item" data-question="{{ item.question | escape }}">
|
||||
<div class="faq-q"><span class="faq-q-text">{{ item.question }}</span><svg class="faq-chevron" viewBox="0 0 24 24"><polyline points="6,9 12,15 18,9"/></svg></div>
|
||||
<div class="faq-a">{{ item.answer }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
141
src/_includes/sections/features.njk
Normal file
141
src/_includes/sections/features.njk
Normal file
@@ -0,0 +1,141 @@
|
||||
|
||||
<section class="features-section" id="features">
|
||||
<div class="features-header silk-reveal">
|
||||
<div class="section-tag">{{ features.headerTag }}</div>
|
||||
<h2 class="section-title">{{ features.title }}</h2>
|
||||
<p class="section-sub">{{ features.subtitle }}</p>
|
||||
</div>
|
||||
<div class="sticky-layout">
|
||||
<div class="sticky-cards">
|
||||
|
||||
{% for feature in features.features %}
|
||||
{% if loop.first %}
|
||||
<div class="sticky-card active" data-panel="{{ loop.index0 }}">
|
||||
{% else %}
|
||||
<div class="sticky-card" data-panel="{{ loop.index0 }}">
|
||||
{% endif %}
|
||||
<div class="sticky-card-icon">
|
||||
{{ feature.icon | safe }}
|
||||
</div>
|
||||
<h3>{{ feature.title }}</h3>
|
||||
<p>{{ feature.description }}</p>
|
||||
<div class="sticky-card-pills">
|
||||
{% for pill in feature.pills %}
|
||||
<span class="sc-pill">{{ pill }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="sticky-panel-wrap">
|
||||
<div class="sticky-panel">
|
||||
<div class="panel-topbar">
|
||||
<div class="panel-dots">
|
||||
<span style="background:#E85A5A"></span>
|
||||
<span style="background:#F0A030"></span>
|
||||
<span style="background:#3DCC8E"></span>
|
||||
</div>
|
||||
<span style="font-size:11px;color:var(--text3);margin-left:8px" id="panelLabel">{{ features.features[0].panelLabel }}</span>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
|
||||
{% for feature in features.features %}
|
||||
{% if loop.first %}
|
||||
<div class="panel-view active" id="panel-{{ loop.index0 }}">
|
||||
{% else %}
|
||||
<div class="panel-view" id="panel-{{ loop.index0 }}">
|
||||
{% endif %}
|
||||
|
||||
{% if feature.panel.stats %}
|
||||
<div class="pm-row">
|
||||
{% for stat in feature.panel.stats %}
|
||||
<div class="pm-card">
|
||||
<div class="pm-label">{{ stat.label }}</div>
|
||||
<div class="pm-val">{{ stat.value }}</div>
|
||||
{% if stat.positive %}
|
||||
<div class="pm-change" style="color:var(--green)">{{ stat.change }}</div>
|
||||
{% else %}
|
||||
<div class="pm-change" style="color:var(--text3)">{{ stat.change }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if feature.panel.transactions %}
|
||||
<div class="pm-list">
|
||||
{% for tx in feature.panel.transactions %}
|
||||
<div class="pm-list-item">
|
||||
<div class="pm-list-icon" style="background:{{ tx.iconBg }};color:{{ tx.iconColor }};font-size:12px">{{ tx.icon }}</div>
|
||||
<div class="pm-list-info">
|
||||
<div class="pm-list-name">{{ tx.name }}</div>
|
||||
<div class="pm-list-sub">{{ tx.sub }}</div>
|
||||
</div>
|
||||
{% if tx.positive %}
|
||||
<div class="pm-list-amt" style="color:var(--green)">{{ tx.amount }}</div>
|
||||
{% else %}
|
||||
<div class="pm-list-amt" style="color:var(--text2)">{{ tx.amount }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if feature.panel.chartData %}
|
||||
<div class="pm-chart-mini">
|
||||
<div class="pm-label">Volume trend — 8 weeks</div>
|
||||
<div class="pm-sparkline" id="sparkline"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if feature.panel.revenue %}
|
||||
<div style="display:flex;flex-direction:column;gap:8px">
|
||||
{% for rev in feature.panel.revenue %}
|
||||
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:8px;padding:10px 12px">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">
|
||||
<span style="font-size:12px;color:var(--text2)">{{ rev.label }}</span>
|
||||
<span style="font-size:12px;font-weight:600">{{ rev.value }}</span>
|
||||
</div>
|
||||
<div class="pm-bar-wrap"><div class="pm-bar" style="width:{{ rev.pct }}%;background:var(--sky)"></div></div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if feature.panel.currencies %}
|
||||
<div class="pm-list">
|
||||
{% for cur in feature.panel.currencies %}
|
||||
<div class="pm-list-item">
|
||||
<div class="pm-list-icon" style="background:{{ cur.bg }};font-size:14px">{{ cur.flag }}</div>
|
||||
<div class="pm-list-info">
|
||||
<div class="pm-list-name">{{ cur.name }}</div>
|
||||
<div class="pm-list-sub">{{ cur.sub }}</div>
|
||||
</div>
|
||||
<div class="pm-list-amt">{{ cur.amount }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if feature.panel.badges %}
|
||||
<div class="pm-security-grid">
|
||||
{% for badge in feature.panel.badges %}
|
||||
<div class="pm-sec-item">
|
||||
{{ badge.icon | safe }}
|
||||
<div class="pm-sec-name">{{ badge.name }}</div>
|
||||
<div class="pm-sec-status">{{ badge.status }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
11
src/_includes/sections/footer.njk
Normal file
11
src/_includes/sections/footer.njk
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
<footer style="padding:24px max(48px, calc((100vw - var(--max-w)) / 2));border-top:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px">
|
||||
<div style="font-size:13px;color:var(--text3)">© {{ site.currentYear }} {{ site.name }}. Built with care.</div>
|
||||
<div style="display:flex;align-items:center;gap:20px">
|
||||
<div style="width:1px;height:14px;background:var(--border)"></div>
|
||||
<div style="display:flex;gap:8px">
|
||||
<a href="https://www.linkedin.com/in/mariosant/" class="social-btn" aria-label="LinkedIn"><svg viewBox="0 0 24 24"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"/><rect x="2" y="9" width="4" height="12"/><circle cx="4" cy="4" r="2"/></svg></a>
|
||||
<a href="https://github.com/mariosant" class="social-btn" aria-label="GitHub"><svg viewBox="0 0 24 24"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
116
src/_includes/sections/hero.njk
Normal file
116
src/_includes/sections/hero.njk
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
<section class="hero" id="home">
|
||||
<div class="hero-content silk-reveal-left">
|
||||
<div class="hero-badge">
|
||||
<span class="badge-dot"></span>
|
||||
{{ hero.badge }}
|
||||
</div>
|
||||
<h1>{{ hero.headline }}</h1>
|
||||
<p class="hero-sub">{{ hero.subtitle }}</p>
|
||||
<div class="hero-btns">
|
||||
<a href="https://cal.com/mariosant/30min" class="btn-hero">
|
||||
{{ hero.primaryBtn }}
|
||||
{{ hero.primaryBtnIcon | safe }}
|
||||
</a>
|
||||
<a href="#dashboard" class="btn-outline">{{ hero.secondaryBtn }}</a>
|
||||
</div>
|
||||
<div class="hero-trust">
|
||||
<div class="hero-avatars">
|
||||
{% for avatar in hero.trustAvatars %}
|
||||
<span>{{ avatar }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="hero-trust-text"><strong>{{ hero.trustCount }}</strong> {{ hero.trustLabel }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-visual silk-reveal-right">
|
||||
<div class="float-badge fb-left">
|
||||
<div class="float-badge-icon" style="background:{{ hero.floatBadges[0].iconBg }}">
|
||||
{{ hero.floatBadges[0].icon | safe }}
|
||||
</div>
|
||||
<div class="float-badge-info">
|
||||
<div class="val">{{ hero.floatBadges[0].value }}</div>
|
||||
<div class="lbl">{{ hero.floatBadges[0].label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="float-badge fb-right">
|
||||
<div class="float-badge-icon" style="background:{{ hero.floatBadges[1].iconBg }}">
|
||||
{{ hero.floatBadges[1].icon | safe }}
|
||||
</div>
|
||||
<div class="float-badge-info">
|
||||
<div class="val">{{ hero.floatBadges[1].value }}</div>
|
||||
<div class="lbl">{{ hero.floatBadges[1].label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dash-card">
|
||||
<div class="dash-topbar">
|
||||
<div class="dash-dots">
|
||||
<span style="background:#E85A5A"></span>
|
||||
<span style="background:#F0A030"></span>
|
||||
<span style="background:#3DCC8E"></span>
|
||||
</div>
|
||||
<span class="dash-title-bar">{{ hero.dashboard.dashTitle }}</span>
|
||||
<span style="font-size:10px;color:var(--green);font-weight:500">● Live</span>
|
||||
</div>
|
||||
<div class="dash-body">
|
||||
<div class="dash-stats">
|
||||
<div class="dash-stat">
|
||||
<div class="dash-stat-label">Balance</div>
|
||||
<div class="dash-stat-val">{{ hero.dashboard.balance }}</div>
|
||||
<div class="dash-stat-change" style="color:var(--green)">{{ hero.dashboard.balanceChange }}</div>
|
||||
</div>
|
||||
<div class="dash-stat">
|
||||
<div class="dash-stat-label">Sent</div>
|
||||
<div class="dash-stat-val">{{ hero.dashboard.sent }}</div>
|
||||
<div class="dash-stat-change" style="color:var(--text3)">{{ hero.dashboard.sentLabel }}</div>
|
||||
</div>
|
||||
<div class="dash-stat">
|
||||
<div class="dash-stat-label">Received</div>
|
||||
<div class="dash-stat-val">{{ hero.dashboard.received }}</div>
|
||||
<div class="dash-stat-change" style="color:var(--green)">{{ hero.dashboard.receivedChange }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-wrap">
|
||||
<div class="chart-head">
|
||||
<span class="chart-head-title">{{ hero.dashboard.chartTitle }}</span>
|
||||
<span class="chart-badge">{{ hero.dashboard.chartBadge }}</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:flex-end;gap:6px;height:64px">
|
||||
<div style="flex:1;background:rgba(74,158,232,.18);border-radius:3px 3px 0 0;height:55%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.18);border-radius:3px 3px 0 0;height:72%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.18);border-radius:3px 3px 0 0;height:48%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.18);border-radius:3px 3px 0 0;height:88%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.18);border-radius:3px 3px 0 0;height:65%;border-top:2px solid var(--sky)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.25);border-radius:3px 3px 0 0;height:92%;border-top:2px solid var(--sky2)"></div>
|
||||
<div style="flex:1;background:rgba(74,158,232,.35);border-radius:3px 3px 0 0;height:100%;border-top:2px solid var(--sky2)"></div>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:space-between;margin-top:5px">
|
||||
<span style="font-size:10px;color:var(--text3)">Mon</span>
|
||||
<span style="font-size:10px;color:var(--text3)">Tue</span>
|
||||
<span style="font-size:10px;color:var(--text3)">Wed</span>
|
||||
<span style="font-size:10px;color:var(--text3)">Thu</span>
|
||||
<span style="font-size:10px;color:var(--text3)">Fri</span>
|
||||
<span style="font-size:10px;color:var(--text3)">Sat</span>
|
||||
<span style="font-size:10px;color:var(--sky)">Today</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tx-list">
|
||||
{% for tx in hero.dashboard.transactions %}
|
||||
<div class="tx-item">
|
||||
<div class="tx-icon" style="background:{{ tx.iconBg }};color:{{ tx.iconColor }}">{{ tx.icon }}</div>
|
||||
<div class="tx-info">
|
||||
<div class="tx-name">{{ tx.name }}</div>
|
||||
<div class="tx-date">{{ tx.date }}</div>
|
||||
</div>
|
||||
{% if tx.positive %}
|
||||
<div class="tx-amount" style="color:var(--green)">{{ tx.amount }}</div>
|
||||
{% else %}
|
||||
<div class="tx-amount" style="color:var(--red)">{{ tx.amount }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
7
src/_includes/sections/logos.njk
Normal file
7
src/_includes/sections/logos.njk
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
<div class="logos-section">
|
||||
<div class="logos-label">{{ logos.label }}</div>
|
||||
<div class="logos-track-wrap">
|
||||
<div class="logos-track" id="logosTrack"></div>
|
||||
</div>
|
||||
</div>
|
||||
10
src/_includes/sections/mobile-menu.njk
Normal file
10
src/_includes/sections/mobile-menu.njk
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
<div class="mobile-menu" id="mobileMenu">
|
||||
{% for link in navigation.links %}
|
||||
<a href="{{ link.href }}">{{ link.label }}</a>
|
||||
{% endfor %}
|
||||
<div class="m-btns">
|
||||
<a href="https://cal.com/mariosant/30min" class="btn-ghost">{{ navigation.cta.signIn }}</a>
|
||||
<a href="https://cal.com/mariosant/30min" class="btn-primary">{{ navigation.mobileCta }}</a>
|
||||
</div>
|
||||
</div>
|
||||
21
src/_includes/sections/nav.njk
Normal file
21
src/_includes/sections/nav.njk
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
<nav id="mainNav">
|
||||
<a href="#" class="nav-logo">
|
||||
<div class="nav-logo-mark">
|
||||
{{ navigation.logo.mark | safe }}
|
||||
</div>
|
||||
{{ site.name }}
|
||||
</a>
|
||||
<div class="nav-links">
|
||||
{% for link in navigation.links %}
|
||||
<a href="{{ link.href }}">{{ link.label }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="nav-cta">
|
||||
<a href="https://cal.com/mariosant/30min" class="btn-ghost">{{ navigation.cta.signIn }}</a>
|
||||
<a href="https://cal.com/mariosant/30min" class="btn-primary">{{ navigation.cta.getStarted }}</a>
|
||||
</div>
|
||||
<button class="hamburger" id="hamburger" aria-label="Open menu" aria-expanded="false">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
</nav>
|
||||
40
src/_includes/sections/pricing.njk
Normal file
40
src/_includes/sections/pricing.njk
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
<section class="pricing-section" id="pricing">
|
||||
<div style="text-align:center; margin-bottom: 2rem">
|
||||
<div class="section-tag">{{ pricing.headerTag }}</div>
|
||||
<h2 class="section-title">{{ pricing.title }}</h2>
|
||||
<p class="section-sub">{{ pricing.subtitle }}</p>
|
||||
</div>
|
||||
<div class="pricing-grid">
|
||||
{% for tier in pricing.tiers %}
|
||||
{% if tier.featured %}
|
||||
<div class="price-card featured">
|
||||
{% else %}
|
||||
<div class="price-card">
|
||||
{% endif %}
|
||||
{% if tier.badge %}
|
||||
<div class="featured-badge">{{ tier.badge }}</div>
|
||||
{% endif %}
|
||||
<div class="price-plan">{{ tier.plan }}</div>
|
||||
<div class="price-amount" style="font-size:36px">{{ tier.price }}</div>
|
||||
{% if tier.subLabel %}
|
||||
<div class="price-period" style="color:var(--text3);font-size:13px">{{ tier.subLabel }}</div>
|
||||
{% elif tier.note %}
|
||||
<div class="price-period" style="color:var(--text3);font-size:12px">{{ tier.note }}</div>
|
||||
{% else %}
|
||||
<div class="price-period"> </div>
|
||||
{% endif %}
|
||||
<ul class="price-features">
|
||||
{% for feature in tier.features %}
|
||||
<li><svg viewBox="0 0 16 16"><polyline points="2,8 6,12 14,4"/></svg>{{ feature }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if tier.featured %}
|
||||
<a href="https://cal.com/mariosant/30min" class="price-btn price-btn-primary">{{ tier.cta }}</a>
|
||||
{% else %}
|
||||
<a href="https://cal.com/mariosant/30min" class="price-btn price-btn-ghost">{{ tier.cta }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
21
src/_includes/sections/security.njk
Normal file
21
src/_includes/sections/security.njk
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
<section class="security-section" id="security">
|
||||
<div class="security-inner">
|
||||
<div>
|
||||
<div class="section-tag">{{ security.headerTag }}</div>
|
||||
<h2 class="section-title">{{ security.title }}</h2>
|
||||
<p class="section-sub" style="margin-bottom:24px">{{ security.subtitle }}</p>
|
||||
<a href="#" class="btn-outline" style="display:inline-block">{{ security.ctaText }}</a>
|
||||
</div>
|
||||
<div class="security-badges">
|
||||
{% for badge in security.badges %}
|
||||
<div class="sec-badge">
|
||||
<div class="sec-badge-icon">{{ badge.icon | safe }}</div>
|
||||
<div class="sec-badge-name">{{ badge.name }}</div>
|
||||
<div class="sec-badge-desc">{{ badge.desc }}</div>
|
||||
<div class="sec-badge-status">{{ badge.status }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
17
src/_includes/sections/stats.njk
Normal file
17
src/_includes/sections/stats.njk
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
<section class="stats-section">
|
||||
{% for stat in stats %}
|
||||
<div class="stat-block">
|
||||
<div class="stat-icon">
|
||||
{{ stat.icon | safe }}
|
||||
</div>
|
||||
<div class="stat-num" data-target="{{ stat.target }}" data-prefix="{{ stat.prefix | default('') }}" data-suffix="{{ stat.suffix | default('') }}" data-decimal="{{ stat.decimal | default(0) }}">{{ stat.prefix | default('') }}0{{ stat.suffix | default('') }}</div>
|
||||
<div class="stat-label">{{ stat.label }}</div>
|
||||
<div class="stat-bar-wrap"><div class="stat-bar" style="width:0%;background:{{ stat.trend.color | default('var(--sky)') }}" data-width="{{ stat.barWidth }}"></div></div>
|
||||
<div class="stat-trend" style="color:var(--{{ stat.trend.color | default('green') }})">
|
||||
{{ stat.trend.icon | safe }}
|
||||
{{ stat.trend.text }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
33
src/_includes/sections/testimonials.njk
Normal file
33
src/_includes/sections/testimonials.njk
Normal file
@@ -0,0 +1,33 @@
|
||||
<section class="testimonials-section">
|
||||
<div style="text-align:center">
|
||||
<div class="section-tag">{{ testimonials.headerTag }}</div>
|
||||
<h2 class="section-title">{{ testimonials.title }}</h2>
|
||||
</div>
|
||||
<div class="testi-track-wrap">
|
||||
<div class="testi-track" id="testiTrack">
|
||||
{% for t in testimonials.testimonials %}
|
||||
<div class="testi-card">
|
||||
<div class="testi-stars">
|
||||
{% for i in range(5) %}
|
||||
<svg viewBox="0 0 24 24"><polygon points="12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26"/></svg>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="testi-quote">"{{ t.quote }}"</p>
|
||||
<div class="testi-author">
|
||||
<div class="testi-avatar">{{ t.initials }}</div>
|
||||
<div>
|
||||
<div class="testi-name">{{ t.name }}</div>
|
||||
<div class="testi-role">{{ t.role }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:center;margin-top:32px">
|
||||
<button id="testiToggle" onclick="toggleTestimonials()" aria-label="Pause testimonials" style="background:var(--bg2);border:1px solid var(--border2);color:var(--text2);padding:10px 18px;border-radius:24px;cursor:pointer;display:flex;align-items:center;gap:8px;font-family:'DM Sans',sans-serif;font-size:13px;font-weight:500;transition:border-color .5s var(--silk),color .5s var(--silk)">
|
||||
<svg id="testiIcon" width="14" height="14" fill="currentColor" stroke="none" viewBox="0 0 24 24"><rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="5" width="4" height="14" rx="1"/></svg>
|
||||
<span id="testiLabel">Pause</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
4
src/_includes/sections/ticker.njk
Normal file
4
src/_includes/sections/ticker.njk
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
<div class="ticker">
|
||||
<div class="ticker-track" id="tickerTrack"></div>
|
||||
</div>
|
||||
1173
src/css/style.css
Normal file
1173
src/css/style.css
Normal file
File diff suppressed because it is too large
Load Diff
5
src/images/favicon.svg
Normal file
5
src/images/favicon.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<rect width="32" height="32" rx="8" fill="#0F1319"/>
|
||||
<polyline points="4,24 10,16 16,19 22,10 28,14" fill="none" stroke="#3DCC8E" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="28" cy="14" r="2.5" fill="#3DCC8E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 318 B |
16
src/index.njk
Normal file
16
src/index.njk
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
layout: base.njk
|
||||
---
|
||||
{% include "sections/nav.njk" %}
|
||||
{% include "sections/mobile-menu.njk" %}
|
||||
{% include "sections/hero.njk" %}
|
||||
{% include "sections/logos.njk" %}
|
||||
{% include "sections/stats.njk" %}
|
||||
{% include "sections/features.njk" %}
|
||||
{% include "sections/dashboard.njk" %}
|
||||
{% include "sections/pricing.njk" %}
|
||||
{% include "sections/security.njk" %}
|
||||
{% include "sections/testimonials.njk" %}
|
||||
{% include "sections/app.njk" %}
|
||||
{% include "sections/faq.njk" %}
|
||||
{% include "sections/footer.njk" %}
|
||||
135
src/js/script.js
Normal file
135
src/js/script.js
Normal file
@@ -0,0 +1,135 @@
|
||||
const nav=document.getElementById('mainNav');
|
||||
window.addEventListener('scroll',()=>{
|
||||
nav.classList.toggle('scrolled',window.scrollY>10);
|
||||
});
|
||||
|
||||
const hamburger=document.getElementById('hamburger');
|
||||
const mobileMenu=document.getElementById('mobileMenu');
|
||||
if(hamburger&&mobileMenu){
|
||||
let scrollY=0;
|
||||
hamburger.addEventListener('click',()=>{
|
||||
const open=mobileMenu.classList.contains('open');
|
||||
if(open){
|
||||
mobileMenu.classList.remove('open');
|
||||
hamburger.classList.remove('open');
|
||||
hamburger.setAttribute('aria-expanded','false');
|
||||
document.body.style.position='';
|
||||
document.body.style.top='';
|
||||
window.scrollTo({top:scrollY,behavior:'instant'});
|
||||
} else {
|
||||
scrollY=window.scrollY;
|
||||
document.body.style.position='fixed';
|
||||
document.body.style.top=`-${scrollY}px`;
|
||||
mobileMenu.classList.add('open');
|
||||
hamburger.classList.add('open');
|
||||
hamburger.setAttribute('aria-expanded','true');
|
||||
}
|
||||
});
|
||||
mobileMenu.querySelectorAll('a').forEach(a=>{
|
||||
a.addEventListener('click',()=>{
|
||||
mobileMenu.classList.remove('open');
|
||||
hamburger.classList.remove('open');
|
||||
hamburger.setAttribute('aria-expanded','false');
|
||||
document.body.style.position='';
|
||||
document.body.style.top='';
|
||||
window.scrollTo({top:scrollY,behavior:'instant'});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const stickyCards=document.querySelectorAll('.sticky-card');
|
||||
const panelViews=document.querySelectorAll('.panel-view');
|
||||
const panelLabel=document.getElementById('panelLabel');
|
||||
const panelLabels=['Timeline','Tech','Deliverables','Approach'];
|
||||
if(stickyCards.length&&panelViews.length){
|
||||
stickyCards.forEach((card,i)=>{
|
||||
card.addEventListener('click',()=>{
|
||||
stickyCards.forEach(c=>c.classList.remove('active'));
|
||||
panelViews.forEach(p=>p.classList.remove('active'));
|
||||
card.classList.add('active');
|
||||
document.getElementById('panel-'+i).classList.add('active');
|
||||
if(panelLabel)panelLabel.textContent=panelLabels[i]||'';
|
||||
});
|
||||
});
|
||||
const observer=new IntersectionObserver((entries)=>{
|
||||
entries.forEach(e=>{
|
||||
if(e.isIntersecting){
|
||||
stickyCards.forEach((card,i)=>{
|
||||
const rect=card.getBoundingClientRect();
|
||||
const viewH=window.innerHeight;
|
||||
if(rect.top<viewH*0.6&&rect.bottom>viewH*0.3){
|
||||
stickyCards.forEach(c=>c.classList.remove('active'));
|
||||
panelViews.forEach(p=>p.classList.remove('active'));
|
||||
card.classList.add('active');
|
||||
document.getElementById('panel-'+i).classList.add('active');
|
||||
if(panelLabel)panelLabel.textContent=panelLabels[i]||'';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},{threshold:0.3});
|
||||
stickyCards.forEach(c=>observer.observe(c));
|
||||
}
|
||||
|
||||
const statNums=document.querySelectorAll('.stat-num[data-target]');
|
||||
const statsObs=new IntersectionObserver((entries)=>{
|
||||
entries.forEach(e=>{
|
||||
if(e.isIntersecting){
|
||||
const el=e.target;
|
||||
const target=parseFloat(el.dataset.target);
|
||||
const suffix=el.dataset.suffix||'';
|
||||
const decimal=parseInt(el.dataset.decimal)||0;
|
||||
const prefix=el.dataset.prefix||'';
|
||||
let start=0,duration=1800,startTime=null;
|
||||
function animate(ts){
|
||||
if(!startTime)startTime=ts;
|
||||
const progress=Math.min((ts-startTime)/duration,1);
|
||||
const ease=1-Math.pow(1-progress,3);
|
||||
const val=start+(target-start)*ease;
|
||||
el.textContent=prefix+(decimal?val.toFixed(decimal):Math.round(val))+suffix;
|
||||
if(progress<1)requestAnimationFrame(animate);
|
||||
}
|
||||
requestAnimationFrame(animate);
|
||||
const bar=el.closest('.stat-block').querySelector('.stat-bar');
|
||||
if(bar){setTimeout(()=>{bar.style.width=bar.dataset.width;},200);}
|
||||
statsObs.unobserve(el);
|
||||
}
|
||||
});
|
||||
},{threshold:0.5});
|
||||
statNums.forEach(el=>statsObs.observe(el));
|
||||
|
||||
document.querySelectorAll('.faq-item .faq-q').forEach(el => {
|
||||
el.addEventListener('click', () => {
|
||||
el.closest('.faq-item').classList.toggle('open');
|
||||
});
|
||||
});
|
||||
|
||||
window.toggleAllFaq = function() {
|
||||
const faqList = document.querySelectorAll('.faq-item');
|
||||
let allExpanded = faqList[0] && faqList[0].classList.contains('open');
|
||||
faqList.forEach(el => {
|
||||
allExpanded ? el.classList.remove('open') : el.classList.add('open');
|
||||
});
|
||||
document.getElementById('faqToggleLabel').textContent = allExpanded ? 'Expand all' : 'Collapse all';
|
||||
const icon = document.getElementById('faqToggleIcon');
|
||||
icon.innerHTML = allExpanded
|
||||
? '<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>'
|
||||
: '<line x1="5" y1="12" x2="19" y2="12"/>';
|
||||
};
|
||||
|
||||
const tt=document.getElementById('testiTrack');
|
||||
if(tt){
|
||||
window.toggleTestimonials=function(){
|
||||
tt.style.animationPlayState=tt.style.animationPlayState==='paused'?'running':'paused';
|
||||
};
|
||||
}
|
||||
|
||||
document.querySelectorAll('a[href^="#"]').forEach(a=>{
|
||||
a.addEventListener('click',e=>{
|
||||
const href=a.getAttribute('href');
|
||||
if(href==='#')return;
|
||||
e.preventDefault();
|
||||
const target=document.querySelector(href);
|
||||
if(target)target.scrollIntoView({behavior:'smooth'});
|
||||
});
|
||||
});
|
||||
7
src/robots.njk
Normal file
7
src/robots.njk
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
permalink: /robots.txt
|
||||
---
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: {{ site.url }}/sitemap.xml
|
||||
11
src/sitemap.njk
Normal file
11
src/sitemap.njk
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
permalink: /sitemap.xml
|
||||
---
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>{{ site.url }}/</loc>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
Reference in New Issue
Block a user