diff --git a/public/icons/signal.svg b/public/icons/signal.svg new file mode 100644 index 0000000..cc07d87 --- /dev/null +++ b/public/icons/signal.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/public/review.png b/public/review.png new file mode 100644 index 0000000..41954b9 Binary files /dev/null and b/public/review.png differ diff --git a/public/scripts/text-scramble.js b/public/scripts/text-scramble.js new file mode 100644 index 0000000..0cbf305 --- /dev/null +++ b/public/scripts/text-scramble.js @@ -0,0 +1,99 @@ +function applyScrambleEffect() { + const glitchTextElements = document.querySelectorAll('.glitch-text'); + const glitchTextHoverElements = document.querySelectorAll('.glitch-text-hover'); + + function animateScramble(element, text, duration = 2000) { + const chars = []; + element.innerHTML = ''; // Clear the original text + + // Measure the element's width before animation starts + const preScrambleWidth = element.offsetWidth; + element.style.width = `${preScrambleWidth}px`; + + for (let t = 0; t < text.length; t++) { + const span = document.createElement('span'); + + // Check if the character is a space, then use   to preserve it + span.innerHTML = text[t] === ' ' ? ' ' : text[t]; + chars[t] = span; + span.style.display = 'inline-block'; + element.appendChild(span); + } + + const rand = Math.random; + const SECONDS = 1000; + const FPS = 30; + const animationLength = duration; + + function animate3(k) { + const kk = k * text.length; + for (let i = 0; i < text.length; i++) { + if (kk < i) { + chars[i].innerHTML = String.fromCharCode(~~(65 + rand() * 26)); + } else { + // Preserve spaces with   + chars[i].innerHTML = text[i] === ' ' ? ' ' : text[i]; + } + } + } + + // Animation loop + let start = Date.now(); + function animate() { + const current = Date.now(); + const time = current - start; + const k = time / animationLength; + + if (k < 1) { + setTimeout(animate, SECONDS / FPS); + animate3(k); + } else { + // Ensure the final text is revealed once the animation is complete + for (let i = 0; i < text.length; i++) { + chars[i].innerHTML = text[i] === ' ' ? ' ' : text[i]; + } + // Restore the original width (optional if you want to revert to normal) + element.style.width = 'auto'; + // Allow new hover events after the animation completes + element.isAnimating = false; + } + } + + animate(); + } + + // Use Intersection Observer to observe when the element comes into view + const observer = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const element = entry.target; + const text = element.innerText; + animateScramble(element, text); + observer.unobserve(element); // Stop observing after the animation has been triggered + } + }); + }, { + threshold: 0.1 // Trigger when 10% of the element is visible + }); + + // Observe each glitchTextElement for when it comes into view + glitchTextElements.forEach((element) => { + observer.observe(element); + }); + + glitchTextHoverElements.forEach((element) => { + const text = element.innerText; + + element.isAnimating = false; + + element.addEventListener('mouseenter', () => { + if (!element.isAnimating) { + element.isAnimating = true; // Set flag to prevent re-triggering during animation + animateScramble(element, text, 800); + } + }); + }); + } + + document.addEventListener('DOMContentLoaded', applyScrambleEffect); + \ No newline at end of file diff --git a/src/components/AboutFooter.astro b/src/components/AboutFooter.astro index 199f1f9..6e85303 100644 --- a/src/components/AboutFooter.astro +++ b/src/components/AboutFooter.astro @@ -2,114 +2,147 @@ import * as config from "../config.yaml"; import core from "../core.json"; import contributors from "../contributors.json"; -import { getPersonByGH } from "../lib/core.js"; -import PeopleCarousel from "../components/PeopleCarousel.astro"; +import SpeakerGrid from "./SpeakerGrid.astro"; +import SliderTestimonial from "./SliderTestimonial.astro"; +import MembersGrid from "./MembersGrid.astro"; -function findPerson(src) { - const p = core.people.find((p) => - src.refs?.twitter - ? p.refs?.twitter === src.refs.twitter - : src.refs?.bsky - ? p.refs.bsky === src.refs.bsky - : {} - ); - if (p) { - p.ct = src; - } - return p; -} +// Accept sectionsConfig as a prop +const { + sectionsConfig = [ + { name: "community", visible: true, order: 1 }, + { name: "socialLinks", visible: true, order: 2 }, + { name: "speakers", visible: true, order: 3 }, + { name: "core contributors", visible: true, order: 4 }, + { name: "contributors", visible: true, order: 5 }, + { name: "testimonials", visible: true, order: 6 }, + { name: "membersGrid", visible: true, order: 7 }, + { name: "communityPartners", visible: true, order: 8 }, + ], +} = Astro.props; -function personLink(person) { - return person.refs?.twitter - ? `https://twitter.com/${person.refs.twitter}` - : person.refs?.bsky - ? `https://bsky.app/profile/${person.refs.bsky}` - : "#"; -} +console.log(sectionsConfig); +// Function to sort sections by order +const sortedSections = sectionsConfig + .filter((section) => section.visible) + .sort((a, b) => a.order - b.order); --- - -
-

- Join the Community -

-
{config.landing.community}
+ +
{config.landing.community}
+
+ )} -

Speakers

-
- { - core.people - .filter((p) => !core.teams["core-team"].includes(p.id)) - .filter((p) => p.imageUrl) - .map((person) => ( -
- - - -
- )) - } -
- -
- -
- -

Git Contributors

-
- { - // filter(p => !core.teams['core-team'].includes(getPersonByGH(p.login)?.id)) - contributors.items.map((contrib) => ( -
- - + {section.name === "socialLinks" && ( + - )) - } -
+ )} -
- - - -
-
+ {section.name === "speakers" && ( +
+

Speakers

+ +
+ )} + + {section.name === "core contributors" && ( +
+

Core Contributors

+ +
+ )} + + {section.name === "contributors" && ( +
+

Contributors

+
+ {contributors.items.map((contrib) => ( +
+ + + +
+ ))} +
+
+ + + +
+
+ )} + + {section.name === "testimonials" && ( +
+

+ What People Have To Say About US +

+ +
+ )} + + {section.name === "membersGrid" && ( +
+

Members

+ +
+ )} + + )) +} diff --git a/src/components/AboutItemGrid.astro b/src/components/AboutItemGrid.astro index 14cb84c..6cb53b6 100644 --- a/src/components/AboutItemGrid.astro +++ b/src/components/AboutItemGrid.astro @@ -2,236 +2,137 @@ import AboutItem from "../components/AboutItem.astro"; --- -
- -
-
- General public - Projects - Startupers -
-
- Developers - Audit companies - Investors -
+ +
+
+

+ We cultivate and foster a culture of privacy in web3 making data free + and public. +

+

+ Check our annual reports, infographics, privacy awards, newsletter, and + guidelines. +

+
- - -
-
- -
- - Market stats - - - - Like Crunchbase, but free forever - -
-
+
+
+ +

+ By developing free and open tools,
we empower people to make informed + decisions: +

-
- -
- - Privacy Ranking - - - - Scoring and review of current privacy projects - +
+
+
+
+
-
-
- -
- - Academy - - - Education for general public how to reach privacy - -
-
-
- -
- - Research - - - - Anual reports, Frameworks, Tools, Books - -
-
-
- -
- - Data - - - +
+ PRIVACY EXPLORER +
+ For Projects, Use-case list, Market & Funding info
- - -
-
- -
- - Advocacy - - - - Branding “decentralization = privacy” - -
-
-
- -
- - Events - - - - Meetups, Summits, Hackathons, Camps - +
+
+
+
-
-
- -
- - Ecosystems collaboration - - - Networks, Alliances, Media -
-
-
- -
- - Standartisation - - - - Privacy-features, security audit (example) - -
-
-
- -
- - Incubation - - - Product managers facilitation, Business sustainability +
+
+ + HACKATHON IDEA GENERATOR + +
+ Helps developers build applications that address real-world + problems, that people will actually use.
- - -
-
-
- - GENERAL PUBLIC - -
    -
  • Milions of educated users
  • -
  • Higher privacy culture
  • -
+
+
+
+
-
- - PROJECTS +
+
+ WEEK IN PRIVACY +
+ Weekly newsletter with round-up of the most important news + happening around privacy in Web3 -
    -
  • Better privacy features
  • -
  • New use-cases
  • -
  • Efficient demos
  • -
-
-
- - SECURITY AUDIT COMPANIES - -
    -
  • New “privacy audit” category
  • -
  • Significant growth of audited projects.
  • -
-
-
-
-
- - DEVELOPERS - -
    -
  • More devs building privacy
  • -
  • More sustainable projects.
  • -
-
-
- - STARTUPERS - -
    -
  • More privacy-oriented projects
  • -
  • Longer runway
  • -
- -
+
+ + + + + +
+
+

+ We make privacy accessible for everyone, empowering people to learn and + implement best practices effectively. +

+

+ From mentoring at hackathons, guidelines for developers, and the + Cypherpunk Academy - we offer training, incubation, and acceleration + programs. +

+ +
+
+
diff --git a/src/components/SliderTestimonial.astro b/src/components/SliderTestimonial.astro new file mode 100644 index 0000000..6828b84 --- /dev/null +++ b/src/components/SliderTestimonial.astro @@ -0,0 +1,176 @@ +--- +const testimonials = [ + { + author: "Matteo", + text: `balance between Transparency and Privacy, accountable and unaccountable, manifest and secret, convex and concave, 1 and 0 is one of the most fun puzzles.`, + imageUrl: "/review.png", + }, + { + author: "Jane", + text: `This platform has opened my eyes to the potential of blockchain technology in a way that I never imagined. The community is vibrant and full of innovation.`, + imageUrl: "/review.png", + }, + { + author: "Alex", + text: `It's amazing to see how much transparency can coexist with privacy, and this is the best representation of how it can work. Great work!`, + imageUrl: "/review.png", + }, +]; + +let currentTestimonial = 0; +--- + +
+
+
+
+ Review Image +
+
+
+

+ {testimonials[currentTestimonial].author}: +

+

+ "{testimonials[currentTestimonial].text}" +

+
+
+
+ + +
+ +
+
+ +
+ +
+ { + testimonials.map((_, index) => ( +
+
+
+ + diff --git a/src/components/SpeakerGrid.astro b/src/components/SpeakerGrid.astro new file mode 100644 index 0000000..d8d008e --- /dev/null +++ b/src/components/SpeakerGrid.astro @@ -0,0 +1,49 @@ +--- +const { people, team } = Astro.props; + +// Filter the people and limit the results to 12 +const filteredPeople = people + .filter((p) => !team.includes(p.id)) + .filter((p) => p.imageUrl) + .slice(0, 12); // Limit to the first 12 people + +function personLink(person) { + return person.refs?.twitter + ? `https://twitter.com/${person.refs.twitter}` + : person.refs?.bsky + ? `https://bsky.app/profile/${person.refs.bsky}` + : "#"; +} + +function truncateCaption(caption) { + if (!caption) return ""; + const words = caption.split(" "); + if (words.length > 10) { + return words.slice(0, 20).join(" ") + "..."; + } + return caption; +} +--- + +
+ {filteredPeople.map((person) => ( +
+ + {person.name} + +
+

{person.name}

+ {person.refs && person.refs.twitter && ( +

@{person.refs.twitter}

+ )} +

{truncateCaption(person.caption)}

+
+
+ ))} +
diff --git a/src/config.yaml b/src/config.yaml index b4c2795..08749e0 100644 --- a/src/config.yaml +++ b/src/config.yaml @@ -22,7 +22,7 @@ header: link: news - name: Docs link: docs - - name: Membership + - name: Get Involved link: membership url: /membership #- name: Manifesto diff --git a/src/layouts/base.astro b/src/layouts/base.astro index 18c93b3..e1989e5 100644 --- a/src/layouts/base.astro +++ b/src/layouts/base.astro @@ -155,7 +155,9 @@ function genHeading(str) {
{config.hero.text}
@@ -167,7 +169,6 @@ function genHeading(str) { <>
- {/**/}
                   
                     {genHeading(title)}
@@ -176,7 +177,7 @@ function genHeading(str) {
               
-

{subtext}

+

{subtext}

) @@ -188,40 +189,79 @@ function genHeading(str) {
-
-
- - -
-
- { - config.footer.menu.map((item) => ( - + + +