Quote Block #12
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import QuoteDecor from "./QuoteDecor";
|
||||
|
||||
const QuoteBlock = ({ className = "" }) => {
|
||||
return (
|
||||
<div
|
||||
className={`py-[var(--spacing-scale-064)] px-[var(--spacing-scale-020)] bg-[var(--color-surface-default-brand-darker-accent)] relative overflow-hidden ${className}`}
|
||||
>
|
||||
{/* DECORATIONS (behind content) */}
|
||||
<QuoteDecor
|
||||
className="pointer-events-none absolute z-0
|
||||
left-0 top-0
|
||||
w-full h-full"
|
||||
/>
|
||||
|
||||
<div className="flex flex-col gap-[var(--spacing-scale-024)] relative z-10">
|
||||
<div className="flex flex-col gap-[var(--spacing-scale-020)]">
|
||||
<Image
|
||||
src="assets/Quote_Avatar.svg"
|
||||
alt="Quote Avatar"
|
||||
width={64}
|
||||
height={64}
|
||||
className="filter sepia"
|
||||
/>
|
||||
<blockquote>
|
||||
<p className="font-bricolage-grotesque font-normal text-[18px] leading-[120%] tracking-[0px] text-[var(--color-content-inverse-primary)] -indent-[0.5em] [&>span]:font-bricolage-grotesque">
|
||||
<span>"</span>The rules of decision-making must be open and
|
||||
available to everyone, and this can happen only if they are
|
||||
formalized.<span>"</span>
|
||||
</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
<div className="flex flex-col gap-[var(--spacing-scale-008)]">
|
||||
<p className="font-inter font-normal text-[12px] leading-[120%] tracking-[0.24px] text-[var(--color-content-inverse-primary)] uppercase">
|
||||
Jo Freeman
|
||||
</p>
|
||||
<p className="font-inter font-normal text-[12px] leading-[120%] tracking-[0.24px] text-[var(--color-content-inverse-primary)] uppercase -indent-[0.5em] [&>span]:font-inter">
|
||||
<span>"</span>The Tyranny of Structurelessness<span>"</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuoteBlock;
|
||||
@@ -0,0 +1,42 @@
|
||||
"use client";
|
||||
|
||||
const QuoteDecor = ({ className = "" }) => {
|
||||
return (
|
||||
<svg
|
||||
className={`text-[var(--color-surface-inverse-brand-primary)] opacity-100 ${className}`}
|
||||
viewBox="0 0 1242 163"
|
||||
aria-hidden="true"
|
||||
overflow="visible"
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
>
|
||||
<g fill="currentColor">
|
||||
{/* First ellipse - top left */}
|
||||
<ellipse
|
||||
cx="590"
|
||||
cy="40"
|
||||
rx="90"
|
||||
ry="40"
|
||||
transform="rotate(-35 600 80)"
|
||||
/>
|
||||
{/* Second ellipse - middle */}
|
||||
<ellipse
|
||||
cx="608"
|
||||
cy="100"
|
||||
rx="90"
|
||||
ry="40"
|
||||
transform="rotate(-35 600 80)"
|
||||
/>
|
||||
{/* Third ellipse - bottom right */}
|
||||
<ellipse
|
||||
cx="610"
|
||||
cy="155"
|
||||
rx="90"
|
||||
ry="40"
|
||||
transform="rotate(-35 600 80)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuoteDecor;
|
||||
+19
-13
@@ -1,26 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import SectionHeader from "./SectionHeader";
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import RuleCard from "./RuleCard";
|
||||
import Button from "./Button";
|
||||
import Image from "next/image";
|
||||
|
||||
const RuleStack = ({ children, className = "" }) => {
|
||||
const RuleStack = ({ className = "" }) => {
|
||||
const handleTemplateClick = (templateName) => {
|
||||
console.log(`Template selected: ${templateName}`);
|
||||
// This would typically navigate to template details or open a modal
|
||||
// For now, we'll just log the selection
|
||||
// Basic analytics tracking
|
||||
if (typeof window !== "undefined") {
|
||||
if (window.gtag) {
|
||||
window.gtag("event", "template_click", {
|
||||
template_name: templateName,
|
||||
});
|
||||
}
|
||||
if (window.analytics) {
|
||||
window.analytics.track("Template Clicked", {
|
||||
templateName: templateName,
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log(`${templateName} template clicked`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
<section
|
||||
className={`w-full bg-transparent py-[var(--spacing-scale-032)] px-[var(--spacing-scale-020)] md:py-[var(--spacing-scale-048)] md:px-[var(--spacing-scale-032)] xmd:py-[var(--spacing-scale-056)] xmd:px-[var(--spacing-scale-032)] lg:py-[var(--spacing-scale-064)] lg:px-[var(--spacing-scale-064)] xl:py-[var(--spacing-scale-064)] xl:px-[var(--spacing-scale-096)] flex flex-col gap-[var(--spacing-scale-024)] xmd:gap-[var(--spacing-scale-032)] lg:gap-[var(--spacing-scale-040)] ${className}`}
|
||||
>
|
||||
<SectionHeader
|
||||
title="Popular templates"
|
||||
subtitle="These are popular patterns for making decisions in mutual aid and open source communities. You can use them as they are or as a starting place for customizing your own CommunityRule."
|
||||
variant="multi-line"
|
||||
/>
|
||||
<div className="flex flex-col gap-[18px] xmd:grid xmd:grid-cols-2 lg:gap-[var(--spacing-scale-024)]">
|
||||
<RuleCard
|
||||
title="Consensus clusters"
|
||||
@@ -90,7 +96,7 @@ const RuleStack = ({ children, className = "" }) => {
|
||||
See all templates
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import NumberedCards from "./components/NumberedCards";
|
||||
import HeroBanner from "./components/HeroBanner";
|
||||
import LogoWall from "./components/LogoWall";
|
||||
import RuleStack from "./components/RuleStack";
|
||||
import QuoteBlock from "./components/QuoteBlock";
|
||||
|
||||
export default function Page() {
|
||||
const heroBannerData = {
|
||||
@@ -41,6 +42,7 @@ export default function Page() {
|
||||
<LogoWall />
|
||||
<NumberedCards {...numberedCardsData} />
|
||||
<RuleStack />
|
||||
<QuoteBlock />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 41 KiB |
Reference in New Issue
Block a user