Compare commits
6 commits
8d3610b5d8
...
573e0accbc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
573e0accbc | ||
|
|
05bc7089e3 | ||
|
|
1eb526de3b | ||
|
|
5c496129c5 | ||
|
|
52c5163fc2 | ||
|
|
e70d1ead43 |
18
ifttt-src/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
node_modules/
|
||||
.astro/
|
||||
|
||||
# build output (written to ../ifttt)
|
||||
dist/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# env
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# OS/editor
|
||||
.DS_Store
|
||||
14
ifttt-src/astro.config.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { defineConfig } from "astro/config";
|
||||
|
||||
export default defineConfig({
|
||||
site: "https://infrafabric.io",
|
||||
output: "static",
|
||||
outDir: "../ifttt",
|
||||
build: {
|
||||
assets: "assets/_astro",
|
||||
},
|
||||
vite: {
|
||||
plugins: [tailwindcss()],
|
||||
},
|
||||
});
|
||||
6264
ifttt-src/package-lock.json
generated
Normal file
25
ifttt-src/package.json
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "iftrace-site",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.14",
|
||||
"astro": "^5.16.6",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-static": "^0.546.0",
|
||||
"sharp": "^0.34.5",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"tw-animate-css": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.8.1",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
60
ifttt-src/public/assets/if-logo-simple.svg
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1024"
|
||||
height="1024"
|
||||
viewBox="0 0 512 512"
|
||||
role="img"
|
||||
aria-labelledby="title desc"
|
||||
>
|
||||
<title id="title">if. mark</title>
|
||||
<desc id="desc">Stylized “if.” mark with subtle gradient and shadow.</desc>
|
||||
|
||||
<defs>
|
||||
<linearGradient id="ifBlue" x1="70" y1="0" x2="440" y2="0" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#0b253b" />
|
||||
<stop offset="0.44" stop-color="#164d7a" />
|
||||
<stop offset="0.56" stop-color="#1b5a8e" />
|
||||
<stop offset="1" stop-color="#0b253b" />
|
||||
</linearGradient>
|
||||
|
||||
<filter id="ifShadow" x="-40%" y="-40%" width="180%" height="180%">
|
||||
<feOffset in="SourceAlpha" dx="0" dy="14" result="off" />
|
||||
<feGaussianBlur in="off" stdDeviation="12" result="blur" />
|
||||
<feColorMatrix
|
||||
in="blur"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0
|
||||
0 0 0 0 0
|
||||
0 0 0 0 0
|
||||
0 0 0 0.28 0"
|
||||
result="shadow"
|
||||
/>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadow" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!--
|
||||
Mark group:
|
||||
- i (stem + dot)
|
||||
- f (stem + top bar + crossbar)
|
||||
- period dot
|
||||
-->
|
||||
<g filter="url(#ifShadow)" transform="translate(75 15)" fill="url(#ifBlue)">
|
||||
<!-- i -->
|
||||
<circle cx="35" cy="125" r="32" />
|
||||
<rect x="0" y="170" width="70" height="220" rx="8" />
|
||||
|
||||
<!-- f -->
|
||||
<rect x="120" y="140" width="86" height="250" rx="10" />
|
||||
<rect x="120" y="110" width="150" height="90" rx="45" />
|
||||
<rect x="120" y="240" width="140" height="80" rx="28" />
|
||||
|
||||
<!-- . -->
|
||||
<circle cx="330" cy="358" r="32" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
73
ifttt-src/public/assets/iftrace-diagram.svg
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" fill="none" role="img" aria-label="IF.Trace verification flow diagram">
|
||||
<defs>
|
||||
<linearGradient id="g" x1="240" y1="180" x2="1360" y2="720" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#60A5FA" stop-opacity="0.95" />
|
||||
<stop offset="0.5" stop-color="#34D399" stop-opacity="0.85" />
|
||||
<stop offset="1" stop-color="#F472B6" stop-opacity="0.85" />
|
||||
</linearGradient>
|
||||
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur stdDeviation="10" result="b" />
|
||||
<feColorMatrix
|
||||
in="b"
|
||||
type="matrix"
|
||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.35 0"
|
||||
/>
|
||||
<feMerge>
|
||||
<feMergeNode />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<style>
|
||||
.card { fill: rgba(2,6,23,0.35); stroke: rgba(255,255,255,0.10); }
|
||||
.title { fill: rgba(255,255,255,0.92); font: 600 28px ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji","Segoe UI Emoji"; }
|
||||
.sub { fill: rgba(255,255,255,0.70); font: 500 18px ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; }
|
||||
.mono { fill: rgba(255,255,255,0.75); font: 500 16px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
|
||||
.stroke { stroke: rgba(226,232,240,0.70); stroke-width: 2.5; }
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<rect x="0" y="0" width="1600" height="900" rx="36" fill="rgba(2,6,23,0.08)" />
|
||||
<path
|
||||
d="M250 740 C 520 560, 740 600, 920 420 C 1080 260, 1240 260, 1360 180"
|
||||
stroke="url(#g)"
|
||||
stroke-width="10"
|
||||
stroke-linecap="round"
|
||||
stroke-opacity="0.35"
|
||||
filter="url(#glow)"
|
||||
/>
|
||||
|
||||
<g>
|
||||
<rect class="card" x="190" y="160" width="360" height="170" rx="22" />
|
||||
<text class="title" x="230" y="218">1) Keep it private</text>
|
||||
<text class="sub" x="230" y="254">You hold the source.</text>
|
||||
<text class="mono" x="230" y="292">source_sha256</text>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<rect class="card" x="620" y="220" width="360" height="170" rx="22" />
|
||||
<text class="title" x="660" y="278">2) Hash the output</text>
|
||||
<text class="sub" x="660" y="314">What you will share.</text>
|
||||
<text class="mono" x="660" y="352">output_sha256</text>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<rect class="card" x="1040" y="160" width="390" height="170" rx="22" />
|
||||
<text class="title" x="1080" y="218">3) Publish a receipt</text>
|
||||
<text class="sub" x="1080" y="254">No login required.</text>
|
||||
<text class="mono" x="1080" y="292">/trace/…</text>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<rect class="card" x="900" y="540" width="530" height="190" rx="22" />
|
||||
<text class="title" x="940" y="602">4) Third party verifies</text>
|
||||
<text class="sub" x="940" y="638">They download bytes and compare hashes.</text>
|
||||
<text class="mono" x="940" y="676">verified == (hashes match)</text>
|
||||
</g>
|
||||
|
||||
<path class="stroke" d="M550 245 C 610 245, 600 260, 620 270" />
|
||||
<path class="stroke" d="M980 270 C 1025 260, 1005 245, 1040 245" />
|
||||
<path class="stroke" d="M1235 330 C 1235 400, 1170 450, 1100 540" />
|
||||
<path class="stroke" d="M800 390 C 800 460, 880 500, 980 540" />
|
||||
|
||||
<text class="sub" x="190" y="800">Integrity claims only: byte-level verification, not interpretation.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
49
ifttt-src/public/assets/iftrace-og.svg
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630" fill="none" role="img" aria-label="IF.Trace — Open verification for confidential work">
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1200" y2="630" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#0B1020" />
|
||||
<stop offset="0.55" stop-color="#07122A" />
|
||||
<stop offset="1" stop-color="#0B1020" />
|
||||
</linearGradient>
|
||||
<linearGradient id="g" x1="210" y1="110" x2="980" y2="520" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#60A5FA" />
|
||||
<stop offset="0.55" stop-color="#34D399" />
|
||||
<stop offset="1" stop-color="#F472B6" />
|
||||
</linearGradient>
|
||||
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur stdDeviation="18" result="b" />
|
||||
<feColorMatrix
|
||||
in="b"
|
||||
type="matrix"
|
||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.45 0"
|
||||
/>
|
||||
<feMerge>
|
||||
<feMergeNode />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
<style>
|
||||
.h1 { fill: rgba(255,255,255,0.96); font: 800 88px ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; letter-spacing: -0.02em; }
|
||||
.sub { fill: rgba(255,255,255,0.78); font: 600 30px ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; }
|
||||
.small { fill: rgba(255,255,255,0.68); font: 600 22px ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; }
|
||||
.mono { fill: rgba(226,232,240,0.80); font: 600 18px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<rect x="0" y="0" width="1200" height="630" rx="44" fill="url(#bg)" />
|
||||
|
||||
<path
|
||||
d="M165 505 C 380 335, 520 360, 670 250 C 800 155, 930 160, 1040 105"
|
||||
stroke="url(#g)"
|
||||
stroke-width="12"
|
||||
stroke-linecap="round"
|
||||
stroke-opacity="0.45"
|
||||
filter="url(#glow)"
|
||||
/>
|
||||
|
||||
<text class="small" x="110" y="140">IF.Transparent > IF.Traceable > IF.Trustworthy</text>
|
||||
<text class="h1" x="110" y="260">IF.Trace</text>
|
||||
<text class="sub" x="110" y="320">Confidential documents → open verification</text>
|
||||
<text class="mono" x="110" y="390">source_sha256 → output_sha256 → /trace/…</text>
|
||||
<text class="small" x="110" y="460">3rd party audit trails, without publishing the source.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
141
ifttt-src/public/review/index.md
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
---
|
||||
title: IF.Trace External Review Packet
|
||||
last_updated_utc: 2025-12-31
|
||||
site: https://infrafabric.io/
|
||||
packet: https://infrafabric.io/review/
|
||||
raw_packet: https://infrafabric.io/review/index.md
|
||||
---
|
||||
|
||||
# IF.Trace External Review Packet (Public)
|
||||
|
||||
This packet exists because many “AI browser / fetch” tools cannot load a live site reliably, even when it is static HTML.
|
||||
|
||||
If you cannot fetch `https://infrafabric.io/` in your environment, use this packet instead. It contains the live URLs, the current plain-language intent, and screenshots.
|
||||
|
||||
## 1) What You Are Reviewing (plain description)
|
||||
|
||||
IF.Trace is a small public website for a verification protocol.
|
||||
|
||||
Goal: **let a third party verify the integrity of confidential work without getting logins**.
|
||||
|
||||
The promise is intentionally narrow:
|
||||
- If the bytes someone downloads match the hashes on the receipt, it is verified.
|
||||
- IF.Trace does **not** claim “correctness” or “truth” of the content.
|
||||
|
||||
## 2) Who The Buyer Is (working assumption)
|
||||
|
||||
Primary buyers we are optimizing for:
|
||||
- people responsible for external review outcomes (procurement / audit / legal / security / research review)
|
||||
- people who get blamed when proof is missing later
|
||||
|
||||
People we are not optimizing for:
|
||||
- casual readers
|
||||
- “cool protocol vibes” audiences
|
||||
|
||||
## 3) Languages
|
||||
|
||||
Live language options:
|
||||
- English (default)
|
||||
- French (`/fr/`)
|
||||
|
||||
Request to reviewers:
|
||||
- evaluate whether the language feels like “buyer language” in both EN and FR
|
||||
- flag any phrases that sound technical, salesy, or “inside baseball”
|
||||
|
||||
## 4) Site Map (what exists)
|
||||
|
||||
Main routes (public):
|
||||
- Home: `https://infrafabric.io/`
|
||||
- Sector: `https://infrafabric.io/verticals/`
|
||||
- Pricing: `https://infrafabric.io/pricing/`
|
||||
- API / developer surface: `https://infrafabric.io/api/`
|
||||
- Whitepaper: `https://infrafabric.io/whitepaper/`
|
||||
- About: `https://infrafabric.io/about/`
|
||||
- Governance: `https://infrafabric.io/governance/`
|
||||
- Review packet (this): `https://infrafabric.io/review/`
|
||||
- FR: `https://infrafabric.io/fr/`
|
||||
|
||||
Header nav is intentionally minimal:
|
||||
- `Sector | Pricing | API`
|
||||
|
||||
## 5) Current “Home Page” Intent (the core promise)
|
||||
|
||||
What we want the user to understand quickly:
|
||||
- This is a way to share proof with outsiders (no login).
|
||||
- The verification is a simple yes/no integrity check (hashes match).
|
||||
- It supports offline bundles for review environments.
|
||||
|
||||
If any of that reads unclear, untrustworthy, or “too clever”, call it out.
|
||||
|
||||
## 6) Screenshots (desktop + mobile)
|
||||
|
||||
Desktop:
|
||||
- Home: `https://infrafabric.io/review/screens/desktop/home.png`
|
||||
- Sector: `https://infrafabric.io/review/screens/desktop/verticals.png`
|
||||
- Pricing: `https://infrafabric.io/review/screens/desktop/pricing.png`
|
||||
- API: `https://infrafabric.io/review/screens/desktop/api.png`
|
||||
|
||||
Mobile:
|
||||
- Home: `https://infrafabric.io/review/screens/mobile/home.png`
|
||||
- Sector: `https://infrafabric.io/review/screens/mobile/verticals.png`
|
||||
- Pricing: `https://infrafabric.io/review/screens/mobile/pricing.png`
|
||||
- API: `https://infrafabric.io/review/screens/mobile/api.png`
|
||||
|
||||
Navigation flow (useful for “first 20 seconds” critique):
|
||||
- Desktop: `https://infrafabric.io/review/screens/desktop/flow/01-home.png` → `02-sector.png` → `03-pricing.png` → `04-api.png`
|
||||
- Mobile: `https://infrafabric.io/review/screens/mobile/flow/01-home.png` → `02-sector.png` → `03-pricing.png` → `04-api.png`
|
||||
|
||||
## 7) What We Want From You (constructive, objective critique)
|
||||
|
||||
Please answer in a structured way.
|
||||
|
||||
### A) Your model and your limits
|
||||
- Model name and version (if you know it)
|
||||
- Knowledge cutoff (if you know it)
|
||||
- Can you fetch live sites / run JavaScript, or only read text?
|
||||
|
||||
### B) “10-second test”
|
||||
After 10 seconds on the home page, can you answer:
|
||||
1) What is this?
|
||||
2) Who is it for?
|
||||
3) What can I do with it right now?
|
||||
|
||||
If not, say what blocked you.
|
||||
|
||||
### C) Trust signals (what makes you believe it)
|
||||
From the page alone:
|
||||
- What feels credible?
|
||||
- What feels vague?
|
||||
- What feels like marketing theatre?
|
||||
|
||||
### D) Cognitive load (mental effort)
|
||||
- What words / sections require re-reading?
|
||||
- What could be removed without losing meaning?
|
||||
- What would you add **only if it reduces confusion**?
|
||||
|
||||
### E) Buyer psychology (the “sold” moment)
|
||||
Assume a cautious buyer who has been burned before:
|
||||
- What makes them say “yes, this is the right shape of solution”?
|
||||
- What makes them say “no, this is risky / unclear / too early”?
|
||||
|
||||
### F) Layout and structure
|
||||
Compare to other “serious verification / trust infrastructure” sites:
|
||||
- Is the layout lean enough?
|
||||
- Is it missing any “minimum viable” credibility elements?
|
||||
- Is the ordering of sections right?
|
||||
|
||||
### G) Language quality (EN + FR)
|
||||
- Any phrases that sound like a bot, like a pitch, or like an academic paper?
|
||||
- Any phrases that sound culturally off in French?
|
||||
|
||||
### H) Concrete patches
|
||||
Provide 3–10 actionable edits (copy or layout). No vague advice.
|
||||
|
||||
## 8) Bias Control (important)
|
||||
|
||||
Please do not be polite. Assume we prefer accuracy over encouragement.
|
||||
|
||||
If you find yourself agreeing with everything, pause and look for weaknesses:
|
||||
- who would *not* trust this, and why?
|
||||
- what could be misunderstood and cause harm?
|
||||
|
||||
BIN
ifttt-src/public/review/screens/desktop/about.png
Normal file
|
After Width: | Height: | Size: 545 KiB |
BIN
ifttt-src/public/review/screens/desktop/api.png
Normal file
|
After Width: | Height: | Size: 696 KiB |
BIN
ifttt-src/public/review/screens/desktop/flow/01-home.png
Normal file
|
After Width: | Height: | Size: 689 KiB |
BIN
ifttt-src/public/review/screens/desktop/flow/02-sector.png
Normal file
|
After Width: | Height: | Size: 485 KiB |
BIN
ifttt-src/public/review/screens/desktop/flow/03-pricing.png
Normal file
|
After Width: | Height: | Size: 369 KiB |
BIN
ifttt-src/public/review/screens/desktop/flow/04-api.png
Normal file
|
After Width: | Height: | Size: 696 KiB |
BIN
ifttt-src/public/review/screens/desktop/fr.png
Normal file
|
After Width: | Height: | Size: 670 KiB |
BIN
ifttt-src/public/review/screens/desktop/governance.png
Normal file
|
After Width: | Height: | Size: 662 KiB |
BIN
ifttt-src/public/review/screens/desktop/home.png
Normal file
|
After Width: | Height: | Size: 689 KiB |
BIN
ifttt-src/public/review/screens/desktop/pricing.png
Normal file
|
After Width: | Height: | Size: 368 KiB |
|
After Width: | Height: | Size: 461 KiB |
BIN
ifttt-src/public/review/screens/desktop/verticals.png
Normal file
|
After Width: | Height: | Size: 484 KiB |
BIN
ifttt-src/public/review/screens/desktop/whitepaper.png
Normal file
|
After Width: | Height: | Size: 532 KiB |
BIN
ifttt-src/public/review/screens/mobile/about.png
Normal file
|
After Width: | Height: | Size: 438 KiB |
BIN
ifttt-src/public/review/screens/mobile/api.png
Normal file
|
After Width: | Height: | Size: 515 KiB |
BIN
ifttt-src/public/review/screens/mobile/flow/01-home.png
Normal file
|
After Width: | Height: | Size: 387 KiB |
BIN
ifttt-src/public/review/screens/mobile/flow/02-sector.png
Normal file
|
After Width: | Height: | Size: 384 KiB |
BIN
ifttt-src/public/review/screens/mobile/flow/03-pricing.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
ifttt-src/public/review/screens/mobile/flow/04-api.png
Normal file
|
After Width: | Height: | Size: 515 KiB |
BIN
ifttt-src/public/review/screens/mobile/fr.png
Normal file
|
After Width: | Height: | Size: 358 KiB |
BIN
ifttt-src/public/review/screens/mobile/governance.png
Normal file
|
After Width: | Height: | Size: 531 KiB |
BIN
ifttt-src/public/review/screens/mobile/home.png
Normal file
|
After Width: | Height: | Size: 387 KiB |
BIN
ifttt-src/public/review/screens/mobile/pricing.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 298 KiB |
BIN
ifttt-src/public/review/screens/mobile/verticals.png
Normal file
|
After Width: | Height: | Size: 383 KiB |
BIN
ifttt-src/public/review/screens/mobile/whitepaper.png
Normal file
|
After Width: | Height: | Size: 394 KiB |
64
ifttt-src/src/components/blocks/article-1.astro
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
title?: string
|
||||
description?: string
|
||||
item?: {
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, title, description, image, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} style={{ "--container": "672px" }}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
{title && <h1>{title}</h1>}
|
||||
{description && <p>{description}</p>}
|
||||
</SectionProse>
|
||||
<Item class="p-0">
|
||||
<ItemMedia>
|
||||
<Avatar class="size-10">
|
||||
<AvatarImage src={item?.image?.src} alt={item?.image?.alt} />
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{item?.title}</ItemTitle>
|
||||
<ItemDescription>{item?.description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 672px) 672px, 100vw" priority {...image} />
|
||||
</SectionMedia>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
</Section>
|
||||
64
ifttt-src/src/components/blocks/article-2.astro
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
title?: string
|
||||
description?: string
|
||||
item?: {
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, title, description, image, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} style={{ "--container": "672px" }}>
|
||||
<SectionContent class="items-center">
|
||||
<SectionProse class="text-center text-balance">
|
||||
{title && <h1>{title}</h1>}
|
||||
{description && <p>{description}</p>}
|
||||
</SectionProse>
|
||||
<Item class="p-0">
|
||||
<ItemMedia>
|
||||
<Avatar class="size-10">
|
||||
<AvatarImage src={image?.src} alt={image?.alt} />
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{item?.title}</ItemTitle>
|
||||
<ItemDescription>{item?.description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 672px) 672px, 100vw" priority {...image} />
|
||||
</SectionMedia>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
</Section>
|
||||
103
ifttt-src/src/components/blocks/articles-1.astro
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
href?: string
|
||||
title?: string
|
||||
description?: string
|
||||
item?: {
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid>
|
||||
{
|
||||
items?.map(({ title, description, image, href, item }) => (
|
||||
<Tile href={href}>
|
||||
<TileMedia class="aspect-video">
|
||||
<Image sizes="600px" {...image} />
|
||||
</TileMedia>
|
||||
<TileContent>
|
||||
<TileTitle class="line-clamp-2">{title}</TileTitle>
|
||||
<TileDescription class="line-clamp-2">
|
||||
{description}
|
||||
</TileDescription>
|
||||
</TileContent>
|
||||
<Item class="p-0">
|
||||
<ItemMedia>
|
||||
<Avatar class="size-10">
|
||||
<AvatarImage src={item?.image?.src} alt={item?.image?.alt} />
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{item?.title}</ItemTitle>
|
||||
<ItemDescription>{item?.description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
104
ifttt-src/src/components/blocks/articles-2.astro
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
href?: string
|
||||
title?: string
|
||||
description?: string
|
||||
item?: {
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSplit class="@5xl:grid-cols-[2fr_3fr]">
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid size="lg">
|
||||
{
|
||||
items?.map(({ title, description, image, href, item }) => (
|
||||
<Tile href={href}>
|
||||
<TileMedia>
|
||||
<Image sizes="820px" {...image} />
|
||||
</TileMedia>
|
||||
<TileContent>
|
||||
<TileTitle>{title}</TileTitle>
|
||||
<TileDescription>{description}</TileDescription>
|
||||
</TileContent>
|
||||
<Item class="p-0">
|
||||
<ItemMedia>
|
||||
<Avatar class="size-10">
|
||||
<AvatarImage src={item?.image?.src} alt={item?.image?.alt} />
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{item?.title}</ItemTitle>
|
||||
<ItemDescription>{item?.description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
101
ifttt-src/src/components/blocks/articles-3.astro
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
href?: string
|
||||
title?: string
|
||||
description?: string
|
||||
item?: {
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSpread class="@5xl:items-end">
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="-mx-3 -my-2">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }) => (
|
||||
<Button variant="link" {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionSpread>
|
||||
<SectionGrid>
|
||||
{
|
||||
items?.map(({ title, description, image, href, item }) => (
|
||||
<Tile href={href}>
|
||||
<TileMedia>
|
||||
<Image sizes="600px" {...image} />
|
||||
</TileMedia>
|
||||
<TileContent>
|
||||
<TileTitle>{title}</TileTitle>
|
||||
<TileDescription>{description}</TileDescription>
|
||||
</TileContent>
|
||||
<Item class="p-0">
|
||||
<ItemMedia>
|
||||
<Avatar class="size-10">
|
||||
<AvatarImage src={item?.image?.src} alt={item?.image?.alt} />
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{item?.title}</ItemTitle>
|
||||
<ItemDescription>{item?.description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
103
ifttt-src/src/components/blocks/articles-4.astro
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
href?: string
|
||||
title?: string
|
||||
description?: string
|
||||
item?: {
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid>
|
||||
{
|
||||
items?.map(({ title, description, image, href, item }) => (
|
||||
<Tile href={href} variant="floating">
|
||||
<TileMedia class="-mx-6 -mt-6 aspect-video">
|
||||
<Image sizes="600px" {...image} />
|
||||
</TileMedia>
|
||||
<TileContent>
|
||||
<TileTitle class="line-clamp-2">{title}</TileTitle>
|
||||
<TileDescription class="line-clamp-2">
|
||||
{description}
|
||||
</TileDescription>
|
||||
</TileContent>
|
||||
<Item class="p-0">
|
||||
<ItemMedia>
|
||||
<Avatar class="size-10">
|
||||
<AvatarImage src={item?.image?.src} alt={item?.image?.alt} />
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{item?.title}</ItemTitle>
|
||||
<ItemDescription>{item?.description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
25
ifttt-src/src/components/blocks/banner-1.astro
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
import {
|
||||
Banner,
|
||||
BannerContent,
|
||||
BannerDescription,
|
||||
BannerTitle,
|
||||
} from "@/components/ui/banner"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
|
||||
interface Props {
|
||||
icon?: string
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
const { icon, title, description } = Astro.props
|
||||
---
|
||||
|
||||
<Banner>
|
||||
<BannerContent>
|
||||
<Icon class="size-5" name={icon} />
|
||||
<BannerTitle>{title}</BannerTitle>
|
||||
<BannerDescription>{description}</BannerDescription>
|
||||
</BannerContent>
|
||||
</Banner>
|
||||
25
ifttt-src/src/components/blocks/banner-2.astro
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
import {
|
||||
Banner,
|
||||
BannerContent,
|
||||
BannerDescription,
|
||||
BannerTitle,
|
||||
} from "@/components/ui/banner"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
|
||||
interface Props {
|
||||
icon?: string
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
const { icon, title, description } = Astro.props
|
||||
---
|
||||
|
||||
<Banner>
|
||||
<BannerContent class="justify-center pr-6">
|
||||
<Icon class="size-5" name={icon} />
|
||||
<BannerTitle>{title}</BannerTitle>
|
||||
<BannerDescription>{description}</BannerDescription>
|
||||
</BannerContent>
|
||||
</Banner>
|
||||
66
ifttt-src/src/components/blocks/blocks-1.astro
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Section, SectionContent } from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
const { class: className, id, ...props } = Astro.props
|
||||
|
||||
const allBlocks = import.meta.glob("src/components/blocks/**/*.astro", {
|
||||
eager: true,
|
||||
})
|
||||
|
||||
const sortedBlocks = Object.entries(allBlocks).sort(([a], [b]) =>
|
||||
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" })
|
||||
)
|
||||
---
|
||||
|
||||
<Section class={cn("@container flex flex-col px-4 py-8", className)} id={id}>
|
||||
<SectionContent
|
||||
class="grid grid-cols-1 gap-6 @3xl:grid-cols-2 @5xl:grid-cols-3"
|
||||
>
|
||||
{
|
||||
sortedBlocks.map(([path, block]: [string, any]) => {
|
||||
const id = path.split("/").pop()?.split(".")[0]
|
||||
const BlockComponent = block.default
|
||||
return BlockComponent ? (
|
||||
<div class="no-scrollbar flex flex-col gap-2">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<Badge variant="secondary" href={`/blocks/${id}/`}>
|
||||
{id}
|
||||
</Badge>
|
||||
</div>
|
||||
<div
|
||||
id={id}
|
||||
class="relative overflow-hidden rounded-lg border-2 border-dashed"
|
||||
>
|
||||
<div class="bg-background no-scrollbar relative aspect-video overflow-x-hidden">
|
||||
<div class="@container h-full w-[200%] origin-top-left scale-50">
|
||||
<BlockComponent {...props}>
|
||||
<Fragment set:html={props?.html} />
|
||||
</BlockComponent>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null
|
||||
})
|
||||
}
|
||||
</SectionContent>
|
||||
</Section>
|
||||
|
||||
<style>
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
95
ifttt-src/src/components/blocks/blocks-2.astro
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
import fs from "fs"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
import Block from "@/components/block.astro"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
title?: string
|
||||
description?: string
|
||||
items?: any[]
|
||||
}
|
||||
|
||||
const { class: className, id, title, description, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={cn("", className)} id={id}>
|
||||
<SectionSpread>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
{title && <h1>{title}</h1>}
|
||||
{description && <p>{description}</p>}
|
||||
</SectionProse>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
<SectionGrid class="grid-cols-1 sm:grid-cols-1 @6xl:grid-cols-2">
|
||||
{
|
||||
items?.map(({ block, href, ...props }) => {
|
||||
if (!block) return null
|
||||
const fileContent = fs.readFileSync(
|
||||
`src/components/blocks/${block}.astro`,
|
||||
"utf8"
|
||||
)
|
||||
return (
|
||||
<div class="group relative aspect-video overflow-hidden rounded-lg border">
|
||||
<div class="bg-background @container h-full w-[400%] origin-top-left scale-25 @xl:w-[200%] @xl:scale-50">
|
||||
<Block block={block} {...props} />
|
||||
</div>
|
||||
<div class="bg-background absolute bottom-0 left-0 hidden w-full items-center justify-between border-t p-4 text-sm shadow-lg group-hover:flex">
|
||||
<Button variant="outline" size="sm" href={href}>
|
||||
<Icon name="eye" class="[&:is(.copied_&)]:hidden" />
|
||||
{block}
|
||||
</Button>
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
class="copy"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
data-copy={fileContent}
|
||||
>
|
||||
<Icon name="copy" class="[&:is(.copied_&)]:hidden" />
|
||||
<Icon name="check" class="hidden [&:is(.copied_&)]:block" />
|
||||
Copy code
|
||||
</Button>
|
||||
<Button
|
||||
class="copy"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
data-copy={`npx shadcn@latest add @fulldev/${block}`}
|
||||
>
|
||||
<Icon name="terminal" class="[&:is(.copied_&)]:hidden" />
|
||||
<Icon name="check" class="hidden [&:is(.copied_&)]:block" />
|
||||
npx shadcn add
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
|
||||
<script>
|
||||
const buttons = document.querySelectorAll("button.copy")
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
const copy = button.getAttribute("data-copy") || ""
|
||||
navigator.clipboard.writeText(copy)
|
||||
button.classList.add("copied")
|
||||
})
|
||||
})
|
||||
|
||||
sessionStorage.removeItem("closedBanners")
|
||||
</script>
|
||||
93
ifttt-src/src/components/blocks/blocks-3.astro
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
import fs from "fs"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Marquee, MarqueeContent } from "@/components/ui/marquee"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
import Block from "@/components/block.astro"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
title?: string
|
||||
description?: string
|
||||
items?: any[]
|
||||
}
|
||||
|
||||
const { class: className, id, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={cn("", className)} id={id}>
|
||||
<SectionSpread>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
<Marquee class="-mx-(--section-px)">
|
||||
<MarqueeContent pauseOnHover>
|
||||
{
|
||||
items?.map(({ block, href, ...props }) => {
|
||||
if (!block) return null
|
||||
const fileContent = fs.readFileSync(
|
||||
`src/components/blocks/${block}.astro`,
|
||||
"utf8"
|
||||
)
|
||||
return (
|
||||
<div class="group relative aspect-video w-[320px] overflow-hidden rounded-lg border @5xl:w-[640px]">
|
||||
<div class="bg-background @container h-full w-[400%] origin-top-left scale-25 @5xl:w-[200%] @5xl:scale-50">
|
||||
<Block block={block} {...props} />
|
||||
</div>
|
||||
<div class="bg-background absolute bottom-0 left-0 hidden w-full items-center justify-between border-t p-4 text-sm shadow-lg group-hover:flex">
|
||||
<h3 class="text-sm font-medium">
|
||||
<a href={href}>{block}</a>
|
||||
</h3>
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
class="copy"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
data-copy={fileContent}
|
||||
>
|
||||
<Icon name="copy" class="[&:is(.copied_&)]:hidden" />
|
||||
<Icon name="check" class="hidden [&:is(.copied_&)]:block" />
|
||||
Copy code
|
||||
</Button>
|
||||
<Button
|
||||
class="copy"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
data-copy={`npx shadcn add @fulldev/${block}`}
|
||||
>
|
||||
<Icon name="terminal" class="[&:is(.copied_&)]:hidden" />
|
||||
<Icon name="check" class="hidden [&:is(.copied_&)]:block" />
|
||||
npx shadcn add
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</MarqueeContent>
|
||||
</Marquee>
|
||||
</Section>
|
||||
|
||||
<script>
|
||||
const buttons = document.querySelectorAll("button.copy")
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
const copy = button.getAttribute("data-copy") || ""
|
||||
navigator.clipboard.writeText(copy)
|
||||
button.classList.add("copied")
|
||||
})
|
||||
})
|
||||
</script>
|
||||
110
ifttt-src/src/components/blocks/blocks-4.astro
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
import fs from "fs"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Marquee, MarqueeContent } from "@/components/ui/marquee"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
import Block from "@/components/block.astro"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
title?: string
|
||||
description?: string
|
||||
items?: any[]
|
||||
}
|
||||
|
||||
const { class: className, id, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={cn("", className)} id={id}>
|
||||
<SectionSpread>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
<div class="flex flex-col gap-6">
|
||||
{
|
||||
(["left", "right"] as const).map((direction) => (
|
||||
<Marquee class="-mx-(--section-px) mask-x-from-95%">
|
||||
<MarqueeContent
|
||||
class="animation-duration-80000"
|
||||
direction={direction}
|
||||
pauseOnHover
|
||||
>
|
||||
{items?.map(({ block, href, ...props }) => {
|
||||
if (!block) return null
|
||||
const fileContent = fs.readFileSync(
|
||||
`src/components/blocks/${block}.astro`,
|
||||
"utf8"
|
||||
)
|
||||
return (
|
||||
<div class="group relative aspect-video w-[320px] overflow-hidden rounded-lg border @5xl:w-[640px]">
|
||||
<div class="bg-background @container h-full w-[400%] origin-top-left scale-25 @5xl:w-[200%] @5xl:scale-50">
|
||||
<Block block={block} {...props} />
|
||||
</div>
|
||||
<div class="bg-background absolute bottom-0 left-0 hidden w-full items-center justify-between border-t p-4 text-sm shadow-lg group-hover:flex">
|
||||
<h3 class="text-sm font-medium">
|
||||
<a href={href}>{block}</a>
|
||||
</h3>
|
||||
<div class="flex gap-2">
|
||||
<Button
|
||||
class="copy"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
data-copy={fileContent}
|
||||
>
|
||||
<Icon name="copy" class="[&:is(.copied_&)]:hidden" />
|
||||
<Icon
|
||||
name="check"
|
||||
class="hidden [&:is(.copied_&)]:block"
|
||||
/>
|
||||
Copy code
|
||||
</Button>
|
||||
<Button
|
||||
class="copy"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
data-copy={`npx shadcn@latest add @fulldev/${block}`}
|
||||
>
|
||||
<Icon
|
||||
name="terminal"
|
||||
class="[&:is(.copied_&)]:hidden"
|
||||
/>
|
||||
<Icon
|
||||
name="check"
|
||||
class="hidden [&:is(.copied_&)]:block"
|
||||
/>
|
||||
npx shadcn add
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</MarqueeContent>
|
||||
</Marquee>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<script>
|
||||
const buttons = document.querySelectorAll("button.copy")
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
const copy = button.getAttribute("data-copy") || ""
|
||||
navigator.clipboard.writeText(copy)
|
||||
button.classList.add("copied")
|
||||
})
|
||||
})
|
||||
</script>
|
||||
55
ifttt-src/src/components/blocks/contact-1.astro
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
import { AutoForm } from "@/components/ui/auto-form"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
form?: any
|
||||
items?: {
|
||||
icon?: string
|
||||
title?: string
|
||||
description?: string
|
||||
href?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, form, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} style="--section-width: 672px;">
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
</SectionContent>
|
||||
<SectionGrid>
|
||||
{
|
||||
items?.map(({ icon, title, description, href }) => (
|
||||
<Item href={href} variant="outline">
|
||||
<ItemMedia variant="icon">
|
||||
<Icon href={href} name={icon} />
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{title}</ItemTitle>
|
||||
<ItemDescription>{description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
<AutoForm {...form} />
|
||||
</Section>
|
||||
60
ifttt-src/src/components/blocks/contact-2.astro
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
import { AutoForm } from "@/components/ui/auto-form"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
form?: any
|
||||
items?: {
|
||||
icon?: string
|
||||
title?: string
|
||||
description?: string
|
||||
href?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, form, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSplit
|
||||
class="items-start @5xl:grid-cols-[3fr_2fr] @5xl:*:sticky @5xl:*:top-[calc(var(--section-py)+var(--header-height,0px))]"
|
||||
>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionGrid class="flex max-w-md flex-col">
|
||||
{
|
||||
items?.map(({ icon, title, description, href }) => (
|
||||
<Item href={href} variant="muted">
|
||||
<ItemMedia variant="icon">
|
||||
<Icon href={href} name={icon} />
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{title}</ItemTitle>
|
||||
<ItemDescription>{description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</SectionContent>
|
||||
<AutoForm {...form} />
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
69
ifttt-src/src/components/blocks/contact-3.astro
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
import { AutoForm } from "@/components/ui/auto-form"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/components/ui/item"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
form?: any
|
||||
items?: {
|
||||
icon?: string
|
||||
title?: string
|
||||
description?: string
|
||||
href?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, form, items, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSplit class="gap-x-32">
|
||||
<SectionContent class="gap-16">
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionGrid class="max-w-2xl grid-cols-1!">
|
||||
{
|
||||
items?.map(({ icon, title, description, href }) => (
|
||||
<Item href={href} variant="outline">
|
||||
<ItemMedia variant="icon">
|
||||
<Icon href={href} name={icon} />
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{title}</ItemTitle>
|
||||
<ItemDescription>{description}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
<AutoForm {...form} />
|
||||
</SectionContent>
|
||||
<SectionMedia
|
||||
class="-mr-(--section-px) p-1 @5xl:z-90 @5xl:-mt-[calc(var(--section-py)+var(--header-height,0px))]"
|
||||
>
|
||||
<Image {...image} />
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
62
ifttt-src/src/components/blocks/content-1.astro
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 1536px) 1536px, 100vw" {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
68
ifttt-src/src/components/blocks/content-2.astro
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSplit class="@5xl:items-center">
|
||||
<SectionContent class="max-w-xl">
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 768px, (min-width: 1024px) 50vw, 100vw"
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
67
ifttt-src/src/components/blocks/content-3.astro
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSpread class="@5xl:items-end">
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
</SectionContent>
|
||||
<SectionContent>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 1536px) 1536px, 100vw" {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
68
ifttt-src/src/components/blocks/content-4.astro
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSplit class="@5xl:grid-cols-[1fr_2fr] @5xl:items-center">
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 1024px, (min-width: 1024px) 66vw, 100vw"
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
76
ifttt-src/src/components/blocks/content-5.astro
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn(
|
||||
"border-primary/20 my-0 -mt-px rounded-none shadow-none",
|
||||
className
|
||||
)}
|
||||
id={id}
|
||||
variant="floating"
|
||||
>
|
||||
<SectionSplit class="@5xl:items-center">
|
||||
<SectionContent class="max-w-xl">
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "outline" : "ghost"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 768px, (min-width: 1024px) 50vw, 100vw"
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
76
ifttt-src/src/components/blocks/content-6.astro
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn(
|
||||
"border-primary/20 my-0 -mt-px rounded-none shadow-none",
|
||||
className
|
||||
)}
|
||||
id={id}
|
||||
variant="floating"
|
||||
>
|
||||
<SectionSplit class="@5xl:items-center">
|
||||
<SectionContent class="max-w-xl">
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "outline" : "ghost"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia class="@5xl:order-first">
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 768px, (min-width: 1024px) 50vw, 100vw"
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
78
ifttt-src/src/components/blocks/cta-1.astro
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} variant="floating">
|
||||
<SectionContent class="items-center">
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
<SectionProse class="text-center" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
</Section>
|
||||
88
ifttt-src/src/components/blocks/cta-2.astro
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, image, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} variant="floating">
|
||||
<SectionSplit class="@5xl:items-center">
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-4">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-10 ring-2">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
<SectionMedia
|
||||
class="-mx-(--section-px) rounded-none @5xl:-my-(--section-py) @5xl:-ml-0"
|
||||
>
|
||||
<Image sizes="(1536px) 768px, (1024px) 50vw, 100vw" {...image} />
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
82
ifttt-src/src/components/blocks/cta-3.astro
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn("bg-accent/50 shadow-none", className)}
|
||||
id={id}
|
||||
variant="floating"
|
||||
>
|
||||
<SectionSpread class="@5xl:items-center">
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionContent>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "secondary"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
</Section>
|
||||
83
ifttt-src/src/components/blocks/cta-4.astro
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, item, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} variant="floating">
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription class="text-foreground">
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
<SectionMedia class="absolute inset-0 size-full opacity-50">
|
||||
<Image sizes="(1536px) 1536px, 100vw" {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
88
ifttt-src/src/components/blocks/cta-5.astro
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, image, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} variant="floating">
|
||||
<SectionSpread class="@5xl:items-center">
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
</SectionContent>
|
||||
<SectionContent>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription class="text-foreground">
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
<SectionMedia class="absolute inset-0 size-full opacity-50">
|
||||
<Image sizes="(1536px) 1536px, 100vw" {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
78
ifttt-src/src/components/blocks/cta-6.astro
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={cn("bg-accent/50", className)} id={id}>
|
||||
<SectionSpread class="@5xl:items-center">
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionContent>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "secondary"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
</Section>
|
||||
90
ifttt-src/src/components/blocks/cta-7.astro
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, image, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} size="lg">
|
||||
<SectionMedia class="absolute inset-0 size-full rounded-none mask-y-from-0%">
|
||||
<Image sizes="(1536px) 1536px, 100vw" {...image} />
|
||||
</SectionMedia>
|
||||
<SectionSpread class="relative @5xl:items-center">
|
||||
<SectionProse size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionContent class="shrink-0">
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
class="w-full"
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription class="text-foreground">
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
</Section>
|
||||
91
ifttt-src/src/components/blocks/cta-8.astro
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, item } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn(
|
||||
"border-primary/20 my-0 -mt-px rounded-none shadow-none",
|
||||
className
|
||||
)}
|
||||
id={id}
|
||||
variant="floating"
|
||||
size="lg"
|
||||
>
|
||||
<SectionContent
|
||||
class={cn(
|
||||
"before:from-primary/20 relative items-center before:absolute before:top-full before:left-0 before:-z-10 before:h-[200%] before:w-full before:animate-pulse before:rounded-full before:bg-gradient-to-b before:to-transparent before:blur-3xl"
|
||||
)}
|
||||
>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
<SectionProse class="text-center" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "outline"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
</Section>
|
||||
61
ifttt-src/src/components/blocks/faqs-1.astro
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<Accordion>
|
||||
{
|
||||
items?.map(({ title, description }) => (
|
||||
<AccordionItem>
|
||||
<AccordionTrigger>{title}</AccordionTrigger>
|
||||
<AccordionContent>{description}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))
|
||||
}
|
||||
</Accordion>
|
||||
</Section>
|
||||
64
ifttt-src/src/components/blocks/faqs-2.astro
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSplit>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<Accordion>
|
||||
{
|
||||
items?.map(({ title, description }) => (
|
||||
<AccordionItem>
|
||||
<AccordionTrigger>{title}</AccordionTrigger>
|
||||
<AccordionContent>{description}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))
|
||||
}
|
||||
</Accordion>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
61
ifttt-src/src/components/blocks/faqs-3.astro
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSpread class="@5xl:items-end">
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionSpread>
|
||||
<Accordion>
|
||||
{
|
||||
items?.map(({ title, description }) => (
|
||||
<AccordionItem>
|
||||
<AccordionTrigger>{title}</AccordionTrigger>
|
||||
<AccordionContent>{description}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))
|
||||
}
|
||||
</Accordion>
|
||||
</Section>
|
||||
61
ifttt-src/src/components/blocks/faqs-4.astro
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} style="--section-width: 672px;">
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<Accordion>
|
||||
{
|
||||
items?.map(({ title, description }) => (
|
||||
<AccordionItem>
|
||||
<AccordionTrigger>{title}</AccordionTrigger>
|
||||
<AccordionContent>{description}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))
|
||||
}
|
||||
</Accordion>
|
||||
</Section>
|
||||
90
ifttt-src/src/components/blocks/features-1.astro
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileActions,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
icon?: string
|
||||
href?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid>
|
||||
{
|
||||
items?.map(({ title, description, icon, links }) => (
|
||||
<Tile>
|
||||
<TileMedia variant="icon">
|
||||
<Icon name={icon} />
|
||||
</TileMedia>
|
||||
<TileContent>
|
||||
<TileTitle>{title}</TileTitle>
|
||||
<TileDescription>{description}</TileDescription>
|
||||
</TileContent>
|
||||
<TileActions>
|
||||
{links?.map(({ icon, text, href, target }) => (
|
||||
<Button
|
||||
class="h-auto p-0"
|
||||
variant="link"
|
||||
href={href}
|
||||
target={target}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))}
|
||||
</TileActions>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
90
ifttt-src/src/components/blocks/features-2.astro
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileActions,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
icon?: string
|
||||
href?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent class="items-center">
|
||||
<SectionProse class="text-center">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid>
|
||||
{
|
||||
items?.map(({ title, description, icon, links }) => (
|
||||
<Tile class="items-center">
|
||||
<TileMedia variant="icon">
|
||||
<Icon name={icon} />
|
||||
</TileMedia>
|
||||
<TileContent class="items-center text-center text-balance">
|
||||
<TileTitle>{title}</TileTitle>
|
||||
<TileDescription>{description}</TileDescription>
|
||||
</TileContent>
|
||||
<TileActions class="justify-center">
|
||||
{links?.map(({ icon, text, href, target }) => (
|
||||
<Button
|
||||
class="h-auto p-0"
|
||||
variant="link"
|
||||
href={href}
|
||||
target={target}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))}
|
||||
</TileActions>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
58
ifttt-src/src/components/blocks/features-3.astro
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileSplit,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
items?: {
|
||||
href?: string
|
||||
title?: string
|
||||
description?: string
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent class="@5xl:items-center">
|
||||
<SectionProse class="@5xl:text-center">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
</SectionContent>
|
||||
<SectionGrid>
|
||||
{
|
||||
items?.map(({ title, description, href, image }) => (
|
||||
<Tile href={href}>
|
||||
<TileSplit class="items-center">
|
||||
<TileMedia>
|
||||
<Image sizes="230px" {...image} />
|
||||
</TileMedia>
|
||||
<TileContent>
|
||||
<TileTitle>{title}</TileTitle>
|
||||
<TileDescription>{description}</TileDescription>
|
||||
</TileContent>
|
||||
</TileSplit>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
95
ifttt-src/src/components/blocks/features-4.astro
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileActions,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
icon?: string
|
||||
href?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSplit class="@5xl:grid-cols-[1fr_2fr]">
|
||||
<SectionContent
|
||||
class="@5xl:sticky @5xl:top-[calc(var(--section-py)+var(--header-height,0px))]"
|
||||
>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid size="lg">
|
||||
{
|
||||
items?.map(({ title, description, icon, links }) => (
|
||||
<Tile>
|
||||
<TileMedia variant="icon">
|
||||
<Icon name={icon} />
|
||||
</TileMedia>
|
||||
<TileContent>
|
||||
<TileTitle>{title}</TileTitle>
|
||||
<TileDescription>{description}</TileDescription>
|
||||
</TileContent>
|
||||
<TileActions>
|
||||
{links?.map(({ icon, text, href, target }) => (
|
||||
<Button
|
||||
class="h-auto p-0"
|
||||
variant="link"
|
||||
href={href}
|
||||
target={target}
|
||||
>
|
||||
{text}
|
||||
{icon && <Icon name={icon} />}
|
||||
</Button>
|
||||
))}
|
||||
</TileActions>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
100
ifttt-src/src/components/blocks/features-5.astro
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileActions,
|
||||
TileContent,
|
||||
TileDescription,
|
||||
TileMedia,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
icon?: string
|
||||
href?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn(
|
||||
"border-primary/20 my-0 -mt-px rounded-none shadow-none",
|
||||
className
|
||||
)}
|
||||
id={id}
|
||||
variant="floating"
|
||||
>
|
||||
<SectionContent class="items-center">
|
||||
<SectionProse class="text-center">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid>
|
||||
{
|
||||
items?.map(({ title, description, icon, links }) => (
|
||||
<Tile class="items-center">
|
||||
<TileMedia class="bg-primary/5 border-primary/20" variant="icon">
|
||||
<Icon class="text-primary" name={icon} />
|
||||
</TileMedia>
|
||||
<TileContent class="items-center text-center text-balance">
|
||||
<TileTitle>{title}</TileTitle>
|
||||
<TileDescription class="text-foreground">
|
||||
{description}
|
||||
</TileDescription>
|
||||
</TileContent>
|
||||
<TileActions class="justify-center">
|
||||
{links?.map(({ icon, text, href, target }) => (
|
||||
<Button
|
||||
class="h-auto p-0"
|
||||
variant="link"
|
||||
href={href}
|
||||
target={target}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))}
|
||||
</TileActions>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
72
ifttt-src/src/components/blocks/features-6.astro
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
import {
|
||||
Tile,
|
||||
TileDescription,
|
||||
TileSplit,
|
||||
TileTitle,
|
||||
} from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
title?: string
|
||||
description?: string
|
||||
icon?: string
|
||||
href?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid class="grid-cols-1! gap-12">
|
||||
{
|
||||
items?.map(({ title, description }) => (
|
||||
<Tile class="border-t pt-12">
|
||||
<TileSplit>
|
||||
<TileTitle>{title}</TileTitle>
|
||||
<TileDescription>{description}</TileDescription>
|
||||
</TileSplit>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
92
ifttt-src/src/components/blocks/footer-1.astro
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
---
|
||||
import {
|
||||
Footer,
|
||||
FooterDescription,
|
||||
FooterGrid,
|
||||
FooterGroup,
|
||||
FooterGroupLabel,
|
||||
FooterMenu,
|
||||
FooterMenuItem,
|
||||
FooterMenuLink,
|
||||
FooterSplit,
|
||||
} from "@/components/ui/footer"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Logo, LogoImage, LogoText } from "@/components/ui/logo"
|
||||
|
||||
interface Props {
|
||||
logo?: {
|
||||
src?: string
|
||||
alt?: string
|
||||
text?: string
|
||||
href?: string
|
||||
}
|
||||
description?: string
|
||||
socials?: string[]
|
||||
menus?: {
|
||||
text?: string
|
||||
href?: string
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
}[]
|
||||
}[]
|
||||
links?: {
|
||||
href?: string
|
||||
text?: string
|
||||
icon?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { logo, description, links, socials, menus } = Astro.props
|
||||
---
|
||||
|
||||
<Footer>
|
||||
<FooterSplit class="@5xl:grid-cols-[1fr_3fr]">
|
||||
<FooterGroup>
|
||||
<Logo href={logo?.href || "/"}>
|
||||
<LogoImage src={logo?.src} alt={logo?.alt} />
|
||||
<LogoText>{logo?.text}</LogoText>
|
||||
</Logo>
|
||||
<FooterDescription>{description}</FooterDescription>
|
||||
<FooterMenu>
|
||||
{
|
||||
links?.map(({ href, icon, text }) => (
|
||||
<FooterMenuItem>
|
||||
<FooterMenuLink href={href}>
|
||||
<Icon href={href} name={icon} />
|
||||
{text}
|
||||
</FooterMenuLink>
|
||||
</FooterMenuItem>
|
||||
))
|
||||
}
|
||||
</FooterMenu>
|
||||
<FooterMenu orientation="horizontal">
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<FooterMenuItem>
|
||||
<FooterMenuLink href={social}>
|
||||
<Icon href={social} />
|
||||
</FooterMenuLink>
|
||||
</FooterMenuItem>
|
||||
))
|
||||
}
|
||||
</FooterMenu>
|
||||
</FooterGroup>
|
||||
<FooterGrid class="@5xl:justify-end">
|
||||
{
|
||||
menus?.map((menu) => (
|
||||
<FooterGroup>
|
||||
<FooterGroupLabel>{menu.text}</FooterGroupLabel>
|
||||
<FooterMenu>
|
||||
{menu.links?.map(({ href, text }) => (
|
||||
<FooterMenuItem>
|
||||
<FooterMenuLink href={href}>{text}</FooterMenuLink>
|
||||
</FooterMenuItem>
|
||||
))}
|
||||
</FooterMenu>
|
||||
</FooterGroup>
|
||||
))
|
||||
}
|
||||
</FooterGrid>
|
||||
</FooterSplit>
|
||||
</Footer>
|
||||
61
ifttt-src/src/components/blocks/footer-2.astro
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
import {
|
||||
Footer,
|
||||
FooterCopyright,
|
||||
FooterDescription,
|
||||
FooterGroup,
|
||||
FooterMenu,
|
||||
FooterMenuItem,
|
||||
FooterMenuLink,
|
||||
} from "@/components/ui/footer"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Logo, LogoImage, LogoText } from "@/components/ui/logo"
|
||||
|
||||
interface Props {
|
||||
logo?: {
|
||||
src?: string
|
||||
alt?: string
|
||||
text?: string
|
||||
href?: string
|
||||
}
|
||||
description?: string
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
}[]
|
||||
socials?: string[]
|
||||
}
|
||||
|
||||
const { logo, description, links, socials } = Astro.props
|
||||
---
|
||||
|
||||
<Footer class="items-center">
|
||||
<FooterGroup class="items-center">
|
||||
<Logo href={logo?.href || "/"}>
|
||||
<LogoImage src={logo?.src} alt={logo?.alt} />
|
||||
<LogoText>{logo?.text}</LogoText>
|
||||
</Logo>
|
||||
<FooterDescription>{description}</FooterDescription>
|
||||
<FooterMenu orientation="horizontal">
|
||||
{
|
||||
links?.map(({ href, text }) => (
|
||||
<FooterMenuItem>
|
||||
<FooterMenuLink href={href}>{text}</FooterMenuLink>
|
||||
</FooterMenuItem>
|
||||
))
|
||||
}
|
||||
</FooterMenu>
|
||||
<FooterMenu orientation="horizontal">
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<FooterMenuItem>
|
||||
<FooterMenuLink href={social}>
|
||||
<Icon href={social} />
|
||||
</FooterMenuLink>
|
||||
</FooterMenuItem>
|
||||
))
|
||||
}
|
||||
</FooterMenu>
|
||||
</FooterGroup>
|
||||
<FooterCopyright>{logo?.text}</FooterCopyright>
|
||||
</Footer>
|
||||
102
ifttt-src/src/components/blocks/footer-3.astro
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
import {
|
||||
Footer,
|
||||
FooterCopyright,
|
||||
FooterDescription,
|
||||
FooterGrid,
|
||||
FooterGroup,
|
||||
FooterGroupLabel,
|
||||
FooterMenu,
|
||||
FooterMenuItem,
|
||||
FooterMenuLink,
|
||||
FooterSplit,
|
||||
FooterSpread,
|
||||
} from "@/components/ui/footer"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Logo, LogoImage, LogoText } from "@/components/ui/logo"
|
||||
|
||||
interface Props {
|
||||
logo?: {
|
||||
src?: string
|
||||
alt?: string
|
||||
text?: string
|
||||
href?: string
|
||||
}
|
||||
description?: string
|
||||
socials?: string[]
|
||||
menus?: {
|
||||
text?: string
|
||||
href?: string
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
}[]
|
||||
}[]
|
||||
links?: {
|
||||
href?: string
|
||||
text?: string
|
||||
icon?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { logo, description, links, socials, menus } = Astro.props
|
||||
---
|
||||
|
||||
<Footer>
|
||||
<FooterSplit class="@5xl:grid-cols-[1fr_3fr]">
|
||||
<FooterDescription class="text-base">{description}</FooterDescription>
|
||||
<FooterGrid class="@5xl:justify-end">
|
||||
{
|
||||
menus?.map((menu) => (
|
||||
<FooterGroup>
|
||||
<FooterGroupLabel>{menu.text}</FooterGroupLabel>
|
||||
<FooterMenu>
|
||||
{menu.links?.map(({ href, text }) => (
|
||||
<FooterMenuItem>
|
||||
<FooterMenuLink href={href}>{text}</FooterMenuLink>
|
||||
</FooterMenuItem>
|
||||
))}
|
||||
</FooterMenu>
|
||||
</FooterGroup>
|
||||
))
|
||||
}
|
||||
</FooterGrid>
|
||||
</FooterSplit>
|
||||
<Logo class="h-auto max-h-none w-full max-w-none" href={logo?.href || "/"}>
|
||||
<LogoImage
|
||||
src={logo?.src}
|
||||
alt={logo?.alt}
|
||||
sizes="(min-width: 1536px) 1536px, 100vw"
|
||||
class="h-auto max-h-none w-full max-w-none object-contain"
|
||||
/>
|
||||
<LogoText>{logo?.text}</LogoText>
|
||||
</Logo>
|
||||
<FooterSpread>
|
||||
<FooterCopyright>{logo?.text}</FooterCopyright>
|
||||
<FooterMenu
|
||||
orientation="horizontal"
|
||||
class="@5xl:absolute @5xl:left-1/2 @5xl:-translate-x-1/2"
|
||||
>
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<FooterMenuItem>
|
||||
<FooterMenuLink href={social}>
|
||||
<Icon href={social} />
|
||||
</FooterMenuLink>
|
||||
</FooterMenuItem>
|
||||
))
|
||||
}
|
||||
</FooterMenu>
|
||||
<FooterMenu orientation="horizontal">
|
||||
{
|
||||
links?.map(({ href, text }) => (
|
||||
<FooterMenuItem>
|
||||
<FooterMenuLink class="text-xs" href={href}>
|
||||
{text}
|
||||
</FooterMenuLink>
|
||||
</FooterMenuItem>
|
||||
))
|
||||
}
|
||||
</FooterMenu>
|
||||
</FooterSpread>
|
||||
</Footer>
|
||||
200
ifttt-src/src/components/blocks/header-1.astro
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
---
|
||||
import MenuIcon from "lucide-static/icons/menu.svg"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible"
|
||||
import { Header, HeaderActions } from "@/components/ui/header"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Logo, LogoImage, LogoText } from "@/components/ui/logo"
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuContent,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuLink,
|
||||
NavigationMenuList,
|
||||
NavigationMenuSub,
|
||||
NavigationMenuSubItem,
|
||||
NavigationMenuSubLink,
|
||||
NavigationMenuTrigger,
|
||||
} from "@/components/ui/navigation-menu"
|
||||
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
} from "@/components/ui/sidebar"
|
||||
import { ThemeToggle } from "@/components/ui/theme-toggle"
|
||||
|
||||
interface Props {
|
||||
logo?: {
|
||||
src?: string
|
||||
alt?: string
|
||||
text?: string
|
||||
href?: string
|
||||
}
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
socials?: string[]
|
||||
menus?: {
|
||||
text?: string
|
||||
href?: string
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
const { logo, menus, links, socials } = Astro.props
|
||||
---
|
||||
|
||||
<Header>
|
||||
<Logo href={logo?.href || "/"}>
|
||||
<LogoImage src={logo?.src} alt={logo?.alt} />
|
||||
<LogoText>{logo?.text}</LogoText>
|
||||
</Logo>
|
||||
<NavigationMenu class="mr-auto @max-5xl:hidden">
|
||||
<NavigationMenuList>
|
||||
{
|
||||
menus?.map((menu) => (
|
||||
<NavigationMenuItem>
|
||||
{menu.links && menu.links.length > 0 ? (
|
||||
<>
|
||||
<NavigationMenuTrigger
|
||||
class="inline-flex h-8 items-center bg-transparent px-3 py-0"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<NavigationMenuSub>
|
||||
{menu.links?.map((link) => (
|
||||
<NavigationMenuSubItem>
|
||||
<NavigationMenuSubLink href={link.href}>
|
||||
{link.text}
|
||||
</NavigationMenuSubLink>
|
||||
</NavigationMenuSubItem>
|
||||
))}
|
||||
</NavigationMenuSub>
|
||||
</NavigationMenuContent>
|
||||
</>
|
||||
) : (
|
||||
<NavigationMenuLink
|
||||
class="inline-flex h-8 items-center bg-transparent px-3 py-0"
|
||||
variant="trigger"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</NavigationMenuLink>
|
||||
)}
|
||||
</NavigationMenuItem>
|
||||
))
|
||||
}
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
<HeaderActions class="@max-5xl:hidden">
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<>
|
||||
<Button variant="ghost" size="icon-sm" href={social} target="_blank">
|
||||
<Icon href={social} />
|
||||
</Button>
|
||||
</>
|
||||
))
|
||||
}
|
||||
<ThemeToggle />
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === links.length - 1 ? "default" : "outline"}
|
||||
size="sm"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</HeaderActions>
|
||||
<Sheet class="first:ml-auto">
|
||||
<SheetTrigger
|
||||
class="@5xl:hidden"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
name="open-menu-button"
|
||||
>
|
||||
<MenuIcon class="size-5" />
|
||||
</SheetTrigger>
|
||||
<SheetContent class="overflow-y-auto px-4 py-12">
|
||||
<SidebarMenu>
|
||||
{
|
||||
menus?.map((menu) => (
|
||||
<SidebarMenuItem>
|
||||
{menu.links && menu.links.length > 0 ? (
|
||||
<Collapsible>
|
||||
<CollapsibleTrigger>
|
||||
<SidebarMenuButton class="h-10 rounded-md px-4 text-xl">
|
||||
{menu.text}
|
||||
</SidebarMenuButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{menu.links?.map((link) => (
|
||||
<SidebarMenuSubItem>
|
||||
<SidebarMenuSubButton href={link.href}>
|
||||
{link.text}
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
) : (
|
||||
<SidebarMenuButton
|
||||
class="h-10 w-full rounded-md px-4 text-xl has-[>svg]:px-4"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</SidebarMenuButton>
|
||||
)}
|
||||
</SidebarMenuItem>
|
||||
))
|
||||
}
|
||||
</SidebarMenu>
|
||||
<HeaderActions class="flex flex-col gap-2">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === links.length - 1 ? "default" : "secondary"}
|
||||
class="w-full"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</HeaderActions>
|
||||
<HeaderActions>
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<Button variant="ghost" size="icon" href={social}>
|
||||
<Icon href={social} />
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</HeaderActions>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</Header>
|
||||
195
ifttt-src/src/components/blocks/header-2.astro
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
---
|
||||
import MenuIcon from "lucide-static/icons/menu.svg"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible"
|
||||
import { Header, HeaderActions } from "@/components/ui/header"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Logo, LogoImage, LogoText } from "@/components/ui/logo"
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuContent,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuLink,
|
||||
NavigationMenuList,
|
||||
NavigationMenuSub,
|
||||
NavigationMenuSubItem,
|
||||
NavigationMenuSubLink,
|
||||
NavigationMenuTrigger,
|
||||
} from "@/components/ui/navigation-menu"
|
||||
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
} from "@/components/ui/sidebar"
|
||||
import { ThemeToggle } from "@/components/ui/theme-toggle"
|
||||
|
||||
interface Props {
|
||||
logo?: {
|
||||
src?: string
|
||||
alt?: string
|
||||
text?: string
|
||||
href?: string
|
||||
}
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
socials?: string[]
|
||||
menus?: {
|
||||
text?: string
|
||||
href?: string
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
const { logo, menus, links, socials } = Astro.props
|
||||
---
|
||||
|
||||
<Header>
|
||||
<Logo href={logo?.href || "/"}>
|
||||
<LogoImage src={logo?.src} alt={logo?.alt} />
|
||||
<LogoText>{logo?.text}</LogoText>
|
||||
</Logo>
|
||||
<NavigationMenu class="absolute left-1/2 -translate-x-1/2 @max-5xl:hidden">
|
||||
<NavigationMenuList>
|
||||
{
|
||||
menus?.map((menu) => (
|
||||
<NavigationMenuItem>
|
||||
{menu.links && menu.links.length > 0 ? (
|
||||
<>
|
||||
<NavigationMenuTrigger
|
||||
class="inline-flex h-8 items-center bg-transparent px-3 py-0"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<NavigationMenuSub>
|
||||
{menu.links?.map((link) => (
|
||||
<NavigationMenuSubItem>
|
||||
<NavigationMenuSubLink href={link.href}>
|
||||
{link.text}
|
||||
</NavigationMenuSubLink>
|
||||
</NavigationMenuSubItem>
|
||||
))}
|
||||
</NavigationMenuSub>
|
||||
</NavigationMenuContent>
|
||||
</>
|
||||
) : (
|
||||
<NavigationMenuLink
|
||||
class="inline-flex h-8 items-center bg-transparent px-3 py-0"
|
||||
variant="trigger"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</NavigationMenuLink>
|
||||
)}
|
||||
</NavigationMenuItem>
|
||||
))
|
||||
}
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
<HeaderActions class="@max-5xl:hidden">
|
||||
<ThemeToggle />
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<Button variant="ghost" size="icon-sm" href={social} target="_blank">
|
||||
<Icon href={social} />
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === links.length - 1 ? "default" : "ghost"}
|
||||
size="sm"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</HeaderActions>
|
||||
<Sheet>
|
||||
<SheetTrigger
|
||||
class="@5xl:hidden"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
name="open-menu-button"
|
||||
>
|
||||
<MenuIcon class="size-5" />
|
||||
</SheetTrigger>
|
||||
<SheetContent class="overflow-y-auto px-4 py-12">
|
||||
<SidebarMenu>
|
||||
{
|
||||
menus?.map((menu) => (
|
||||
<SidebarMenuItem>
|
||||
{menu.links && menu.links.length > 0 ? (
|
||||
<Collapsible>
|
||||
<CollapsibleTrigger>
|
||||
<SidebarMenuButton>{menu.text}</SidebarMenuButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{menu.links?.map((link) => (
|
||||
<SidebarMenuSubItem>
|
||||
<SidebarMenuSubButton href={link.href}>
|
||||
{link.text}
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
) : (
|
||||
<SidebarMenuButton
|
||||
class="h-10 w-full rounded-md px-4 text-xl has-[>svg]:px-4"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</SidebarMenuButton>
|
||||
)}
|
||||
</SidebarMenuItem>
|
||||
))
|
||||
}
|
||||
</SidebarMenu>
|
||||
<HeaderActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === links.length - 1 ? "default" : "ghost"}
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</HeaderActions>
|
||||
<HeaderActions>
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<Button variant="ghost" size="icon" href={social}>
|
||||
<Icon href={social} />
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</HeaderActions>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</Header>
|
||||
213
ifttt-src/src/components/blocks/header-3.astro
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
---
|
||||
import MenuIcon from "lucide-static/icons/menu.svg"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible"
|
||||
import { Header, HeaderActions } from "@/components/ui/header"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Logo, LogoImage, LogoText } from "@/components/ui/logo"
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuContent,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuLink,
|
||||
NavigationMenuList,
|
||||
NavigationMenuSub,
|
||||
NavigationMenuSubItem,
|
||||
NavigationMenuSubLink,
|
||||
NavigationMenuTrigger,
|
||||
} from "@/components/ui/navigation-menu"
|
||||
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
} from "@/components/ui/sidebar"
|
||||
import { ThemeToggle } from "@/components/ui/theme-toggle"
|
||||
|
||||
interface Props {
|
||||
logo?: {
|
||||
src?: string
|
||||
alt?: string
|
||||
text?: string
|
||||
href?: string
|
||||
}
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
socials?: string[]
|
||||
menus?: {
|
||||
text?: string
|
||||
href?: string
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
const { logo, menus, links, socials } = Astro.props
|
||||
|
||||
const githubStarCount = (
|
||||
await (await fetch("https://api.github.com/repos/fulldotdev/ui")).json()
|
||||
).stargazers_count
|
||||
---
|
||||
|
||||
<Header class="bg-background/60 backdrop-blur-md">
|
||||
<Logo href={logo?.href || "/"}>
|
||||
<LogoImage src={logo?.src} alt={logo?.alt} />
|
||||
<LogoText>{logo?.text}</LogoText>
|
||||
</Logo>
|
||||
<NavigationMenu class="mr-auto @max-5xl:hidden">
|
||||
<NavigationMenuList>
|
||||
{
|
||||
menus?.map((menu) => (
|
||||
<NavigationMenuItem>
|
||||
{menu.links && menu.links.length > 0 ? (
|
||||
<>
|
||||
<NavigationMenuTrigger
|
||||
class="inline-flex h-8 items-center bg-transparent px-3 py-0"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<NavigationMenuSub>
|
||||
{menu.links?.map((link) => (
|
||||
<NavigationMenuSubItem>
|
||||
<NavigationMenuSubLink href={link.href}>
|
||||
{link.text}
|
||||
</NavigationMenuSubLink>
|
||||
</NavigationMenuSubItem>
|
||||
))}
|
||||
</NavigationMenuSub>
|
||||
</NavigationMenuContent>
|
||||
</>
|
||||
) : (
|
||||
<NavigationMenuLink
|
||||
class="inline-flex h-8 items-center bg-transparent px-3 py-0"
|
||||
variant="trigger"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</NavigationMenuLink>
|
||||
)}
|
||||
</NavigationMenuItem>
|
||||
))
|
||||
}
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
<HeaderActions class="@max-5xl:hidden">
|
||||
<ThemeToggle />
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<>
|
||||
<Button variant="ghost" size="icon-sm" href={social} target="_blank">
|
||||
<Icon href={social} />
|
||||
</Button>
|
||||
</>
|
||||
))
|
||||
}
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === links.length - 1 ? "default" : "outline"}
|
||||
size="sm"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
href="https://github.com/fulldotdev/ui"
|
||||
target="_blank"
|
||||
>
|
||||
<Icon name="github" />
|
||||
{githubStarCount}
|
||||
</Button>
|
||||
</HeaderActions>
|
||||
<Sheet class="first:ml-auto @5xl:hidden">
|
||||
<SheetTrigger
|
||||
class="@5xl:hidden"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
name="open-menu-button"
|
||||
>
|
||||
<MenuIcon class="size-5" />
|
||||
</SheetTrigger>
|
||||
<SheetContent class="overflow-y-auto px-4 py-12">
|
||||
<SidebarMenu>
|
||||
{
|
||||
menus?.map((menu) => (
|
||||
<SidebarMenuItem>
|
||||
{menu.links && menu.links.length > 0 ? (
|
||||
<Collapsible>
|
||||
<CollapsibleTrigger>
|
||||
<SidebarMenuButton class="h-10 rounded-md px-4 text-xl">
|
||||
{menu.text}
|
||||
</SidebarMenuButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{menu.links?.map((link) => (
|
||||
<SidebarMenuSubItem>
|
||||
<SidebarMenuSubButton href={link.href}>
|
||||
{link.text}
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
) : (
|
||||
<SidebarMenuButton
|
||||
class="h-10 w-full rounded-md px-4 text-xl has-[>svg]:px-4"
|
||||
href={menu.href}
|
||||
>
|
||||
{menu.text}
|
||||
</SidebarMenuButton>
|
||||
)}
|
||||
</SidebarMenuItem>
|
||||
))
|
||||
}
|
||||
</SidebarMenu>
|
||||
<HeaderActions class="flex flex-col gap-2">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === links.length - 1 ? "default" : "secondary"}
|
||||
class="w-full"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</HeaderActions>
|
||||
<HeaderActions>
|
||||
{
|
||||
socials?.map((social) => (
|
||||
<Button variant="ghost" size="icon" href={social}>
|
||||
<Icon href={social} />
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</HeaderActions>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</Header>
|
||||
67
ifttt-src/src/components/blocks/hero-1.astro
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
link?: {
|
||||
text?: string
|
||||
href?: string
|
||||
icon?: string
|
||||
target?: string
|
||||
}
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
icon?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, link, links, image } = Astro.props
|
||||
|
||||
const { icon: linkIcon, text: linkText, ...linkProps } = link || {}
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent class="items-center">
|
||||
<Badge variant="secondary" {...linkProps}>
|
||||
{linkText}
|
||||
{linkProps.href && linkIcon && <Icon name={linkIcon} />}
|
||||
</Badge>
|
||||
<SectionProse class="text-center text-balance" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 1536px) 1536px, 100vw" priority {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
98
ifttt-src/src/components/blocks/hero-10.astro
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, item, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn("-mt-(--header-height) justify-start", className)}
|
||||
id={id}
|
||||
size="lg"
|
||||
>
|
||||
<SectionSpread class="relative @5xl:items-center">
|
||||
<SectionProse size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionContent class="shrink-0">
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
class="w-full"
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
<SectionMedia
|
||||
class="mask-y-to-black-100% absolute inset-0 size-full rounded-none bg-white mask-y-from-0% dark:bg-black"
|
||||
>
|
||||
<Image sizes="100vw" priority {...image} class="opacity-75" />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
98
ifttt-src/src/components/blocks/hero-11.astro
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, item, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn("justify-start pb-[72cqw] @5xl:pb-[36cqw]", className)}
|
||||
id={id}
|
||||
size="lg"
|
||||
>
|
||||
<SectionSpread class="relative @5xl:items-center">
|
||||
<SectionProse size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionContent class="shrink-0">
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
class="w-full"
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
</SectionSpread>
|
||||
<SectionMedia
|
||||
class="mask-y-to-black-100% absolute inset-0 size-full rounded-none bg-white mask-y-from-0% dark:bg-black"
|
||||
>
|
||||
<Image class="opacity-75" sizes="100vw" priority {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
66
ifttt-src/src/components/blocks/hero-12.astro
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSpread,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
title?: string
|
||||
description?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
class: className,
|
||||
id,
|
||||
title,
|
||||
description,
|
||||
links,
|
||||
image,
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
<Section class={cn("gap-8 pt-8", className)} id={id}>
|
||||
<SectionContent class="border-y py-8">
|
||||
<SectionSpread class="@5xl:items-end">
|
||||
<SectionProse class="text-balance" size="sm">
|
||||
{title && <h1>{title}</h1>}
|
||||
</SectionProse>
|
||||
<SectionProse class="text-muted-foreground text-balance" size="sm">
|
||||
{description && <p>{description}</p>}
|
||||
</SectionProse>
|
||||
<SectionActions class="-my-2 -ml-3 flex-row flex-nowrap">
|
||||
{
|
||||
links?.map(({ href, text, ...link }) => (
|
||||
<Button variant="link" href={href} {...link}>
|
||||
{text}
|
||||
{href && <Icon name="arrow-up-right" />}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionSpread>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 1536px) 1536px, 100vw" priority {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
63
ifttt-src/src/components/blocks/hero-13.astro
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
class: className,
|
||||
id,
|
||||
links,
|
||||
image,
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
<Section class={cn("@5xl:pt-1", className)} id={id}>
|
||||
<SectionSplit class="@5xl:grid-cols-[1fr_3fr] @5xl:items-start">
|
||||
<SectionContent class="pt-(--section-py)">
|
||||
<SectionProse class="text-balance" size="sm">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="-my-2 -ml-3">
|
||||
{
|
||||
links?.map(({ href, text, ...link }) => (
|
||||
<Button variant="link" href={href} {...link}>
|
||||
{text}
|
||||
{href && <Icon name="arrow-up-right" />}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia class="relative z-100 -mr-5">
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 1152px, (min-width: 1024px) 75vw, 100vw"
|
||||
priority
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
70
ifttt-src/src/components/blocks/hero-14.astro
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
link?: {
|
||||
text?: string
|
||||
href?: string
|
||||
icon?: string
|
||||
target?: string
|
||||
}
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
icon?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, link, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent
|
||||
class={cn(
|
||||
"before:from-primary/10 relative items-center before:absolute before:bottom-full before:left-0 before:h-[200%] before:w-full before:animate-pulse before:rounded-full before:bg-gradient-to-t before:to-transparent before:blur-3xl"
|
||||
)}
|
||||
>
|
||||
<Badge variant="secondary" {...link}>
|
||||
{link?.text}
|
||||
{link?.href && <Icon name={link?.icon} />}
|
||||
</Badge>
|
||||
<SectionProse class="text-center text-balance" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "outline"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 1536px) 1536px, 100vw" priority {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
87
ifttt-src/src/components/blocks/hero-2.astro
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
icon?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, item, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent class="items-center">
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
<SectionProse class="text-center text-balance" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 1536px) 1536px, 100vw" priority {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
59
ifttt-src/src/components/blocks/hero-3.astro
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
icon?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} size="lg">
|
||||
<SectionContent class="items-center">
|
||||
<SectionProse class="text-center text-balance" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia class="absolute inset-0 rounded-none bg-white dark:bg-black">
|
||||
<Image
|
||||
class="opacity-50"
|
||||
sizes="(min-width: 1536px) 1536px, 100vw"
|
||||
priority
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
64
ifttt-src/src/components/blocks/hero-4.astro
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
text?: string
|
||||
href?: string
|
||||
icon?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn("justify-center py-[36cqw] @5xl:py-[18cqw]", className)}
|
||||
id={id}
|
||||
size="lg"
|
||||
>
|
||||
<SectionContent class="items-center">
|
||||
<SectionProse class="text-center text-balance" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions class="justify-center">
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia class="absolute inset-0 rounded-none bg-white dark:bg-black">
|
||||
<Image
|
||||
class="opacity-50"
|
||||
sizes="(min-width: 1536px) 1536px, 100vw"
|
||||
priority
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
99
ifttt-src/src/components/blocks/hero-5.astro
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, item, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image sizes="(min-width: 1536px) 1536px, 100vw" priority {...image} />
|
||||
</SectionMedia>
|
||||
</Section>
|
||||
106
ifttt-src/src/components/blocks/hero-6.astro
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, item, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionSplit class="@5xl:items-center">
|
||||
<SectionContent>
|
||||
<SectionProse class="text-balance" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
<SectionMedia>
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 768px, (min-width: 1024px) 50vw, 100vw"
|
||||
priority
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
108
ifttt-src/src/components/blocks/hero-7.astro
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, item, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} size="lg">
|
||||
<SectionSplit class="@5xl:grid-cols-[2fr_3fr] @5xl:items-center">
|
||||
<SectionContent>
|
||||
<SectionProse class="text-balance" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
<SectionMedia
|
||||
class="-mr-(--section-px) rounded-r-none @5xl:-my-(--section-py)"
|
||||
>
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 922px, (min-width: 1024px) 60vw, 100vw"
|
||||
priority
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
72
ifttt-src/src/components/blocks/hero-8.astro
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, links, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id} size="lg">
|
||||
<SectionSplit class="@5xl:grid-cols-[1fr_3fr] @5xl:items-center">
|
||||
<SectionContent>
|
||||
<SectionProse class="text-balance" size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionMedia
|
||||
class="-mr-(--section-px) rounded-r-none @5xl:-my-(--section-py)"
|
||||
>
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 1152px, (min-width: 1024px) 75vw, 100vw"
|
||||
priority
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
111
ifttt-src/src/components/blocks/hero-9.astro
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
} from "@/components/ui/item"
|
||||
import { List, ListItem } from "@/components/ui/list"
|
||||
import { Rating } from "@/components/ui/rating"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionMedia,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
list?: string[]
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
item?: {
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
title?: string
|
||||
}[]
|
||||
rating?: number
|
||||
description?: string
|
||||
}
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
title?: string
|
||||
}
|
||||
}
|
||||
|
||||
const { class: className, id, list, links, item, image } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={cn("-mt-(--header-height)", className)} id={id}>
|
||||
<SectionSplit>
|
||||
<SectionContent class="relative z-10 pt-(--header-height) @5xl:self-center">
|
||||
<SectionProse size="lg">
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<List>
|
||||
{
|
||||
list?.map((item) => (
|
||||
<ListItem>
|
||||
<Icon name="check" />
|
||||
{item}
|
||||
</ListItem>
|
||||
))
|
||||
}
|
||||
</List>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button
|
||||
variant={i === 0 ? "default" : "secondary"}
|
||||
size="lg"
|
||||
{...link}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
<Item class="p-0">
|
||||
<ItemMedia class="-space-x-5">
|
||||
{
|
||||
item?.images?.map((image) => (
|
||||
<Avatar class="ring-background size-11 ring">
|
||||
<AvatarImage {...image} />
|
||||
</Avatar>
|
||||
))
|
||||
}
|
||||
</ItemMedia>
|
||||
<ItemContent class="mt-1">
|
||||
<Rating rating={item?.rating} />
|
||||
<ItemDescription>
|
||||
{item?.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SectionContent>
|
||||
<SectionMedia
|
||||
class="-mx-(--section-px) -my-(--section-py) rounded-none @max-5xl:mask-y-from-50% @5xl:-ml-[25%] @5xl:mask-b-from-50% @5xl:mask-l-from-0%"
|
||||
>
|
||||
<Image
|
||||
sizes="(min-width: 1536px) 768px, (min-width: 1024px) 50vw, 100vw"
|
||||
priority
|
||||
{...image}
|
||||
/>
|
||||
</SectionMedia>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
70
ifttt-src/src/components/blocks/images-1.astro
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
import { Tile, TileContent, TileMedia, TileTitle } from "@/components/ui/tile"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
items?: {
|
||||
href?: string
|
||||
title?: string
|
||||
image?: {
|
||||
src: string
|
||||
alt: string
|
||||
}
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links, items } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={cn("gap-12", className)} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ icon, text, ...link }, i) => (
|
||||
<Button variant={i === 0 ? "default" : "outline"} {...link}>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid class="-mx-5 grid-cols-1 gap-1 @5xl:grid-cols-2">
|
||||
{
|
||||
items?.map(({ href, title, image }) => (
|
||||
<Tile
|
||||
href={href}
|
||||
class="dark relative overflow-hidden bg-black! ring-0!"
|
||||
>
|
||||
<TileMedia class="w-full transition duration-500 ease-in-out group-hover/tile:scale-103">
|
||||
<Image {...image} />
|
||||
</TileMedia>
|
||||
<TileContent class="absolute inset-0 z-10 size-full items-center justify-center p-6 text-center opacity-0 transition duration-500 ease-in-out group-hover/tile:opacity-100">
|
||||
<TileTitle class="text-foreground">{title}</TileTitle>
|
||||
</TileContent>
|
||||
</Tile>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||
62
ifttt-src/src/components/blocks/images-2.astro
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import { Image } from "@/components/ui/image"
|
||||
import {
|
||||
Section,
|
||||
SectionActions,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
SectionSplit,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
images?: {
|
||||
src: string
|
||||
alt: string
|
||||
}[]
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
const { class: className, id, links, images, title, description } = Astro.props
|
||||
---
|
||||
|
||||
<Section
|
||||
class={cn("@5xl:pt-1 -mt-(--header-height) @5xl:gap-1", className)}
|
||||
id={id}
|
||||
>
|
||||
<SectionSplit class="@5xl:grid-cols-[1fr_3fr] @5xl:items-start">
|
||||
<SectionContent
|
||||
class="@5xl:sticky @5xl:top-[calc(24px+var(--header-height,0px))]"
|
||||
>
|
||||
<SectionProse class="text-balance" size="sm">
|
||||
{title && <h1>{title}</h1>}
|
||||
{description && <p>{description}</p>}
|
||||
</SectionProse>
|
||||
<SectionActions>
|
||||
{
|
||||
links?.map(({ href, text, ...link }) => (
|
||||
<Button variant="link" class="h-auto p-0!" href={href} {...link}>
|
||||
{text}
|
||||
{href && <Icon name="arrow-up-right" />}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionActions>
|
||||
</SectionContent>
|
||||
<SectionGrid class="-mx-5 grid-cols-1 gap-1 @5xl:grid-cols-2">
|
||||
{images?.map(({ ...image }) => <Image {...image} />)}
|
||||
</SectionGrid>
|
||||
</SectionSplit>
|
||||
</Section>
|
||||
46
ifttt-src/src/components/blocks/links-1.astro
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Icon } from "@/components/ui/icon"
|
||||
import {
|
||||
Section,
|
||||
SectionContent,
|
||||
SectionGrid,
|
||||
SectionProse,
|
||||
} from "@/components/ui/section"
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
id?: string
|
||||
links?: {
|
||||
icon?: string
|
||||
text?: string
|
||||
href?: string
|
||||
target?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
const { class: className, id, links } = Astro.props
|
||||
---
|
||||
|
||||
<Section class={className} id={id}>
|
||||
<SectionContent>
|
||||
<SectionProse>
|
||||
<slot />
|
||||
</SectionProse>
|
||||
</SectionContent>
|
||||
<SectionGrid class="-mx-4" size="sm">
|
||||
{
|
||||
links?.map(({ icon, text, href, target }) => (
|
||||
<Button
|
||||
class="text-foreground justify-start text-start text-base"
|
||||
variant="link"
|
||||
href={href}
|
||||
target={target}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{text}
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</SectionGrid>
|
||||
</Section>
|
||||