From 9ebff3c1ae8c34e72fbbbca46d77ac75d09a7f41 Mon Sep 17 00:00:00 2001 From: therealwolf42 <76-therealwolf42@users.noreply.gitlab.syncad.com> Date: Fri, 14 Nov 2025 12:48:25 +0100 Subject: [PATCH] add core-dev meetings, fix mobile menu, fix scroll indicator --- messages/en.json | 2 +- src/app/[locale]/about/page.tsx | 54 ++++++ src/app/[locale]/core-dev-meetings/page.tsx | 90 ++++++++++ src/app/[locale]/page.tsx | 7 +- src/components/ScrollIndicator.tsx | 33 +++- src/components/mobile-menu/MobileMenu.tsx | 34 ++-- .../navigation/MobileNavigation.tsx | 157 ++++++++++++++++++ src/components/navigation/Navigation.tsx | 21 ++- src/lib/data/coredevmeetings.ts | 58 +++++++ src/lib/data/navigation.ts | 5 + src/lib/data/videos.ts | 28 ++++ 11 files changed, 458 insertions(+), 31 deletions(-) create mode 100644 src/app/[locale]/core-dev-meetings/page.tsx create mode 100644 src/components/navigation/MobileNavigation.tsx create mode 100644 src/lib/data/coredevmeetings.ts create mode 100644 src/lib/data/videos.ts diff --git a/messages/en.json b/messages/en.json index 403ec07..a4521db 100644 --- a/messages/en.json +++ b/messages/en.json @@ -37,7 +37,7 @@ "featureFast": "Fast", "featureFastText": "Hive has 3 second block times with transactions confirmed within milliseconds due to one-block irreversibility, allowing for a seamless experience.", "featureScalable": "Scalable", - "featureScalableText": "Efficiency is key. Hive is optimized for sustainability and flexibility with layered solutions.", + "featureScalableText": "Efficiency is key. Hive is optimized for sustainability and flexibility with layered solutions. Nodes can run on modest hardware, keeping the network accessible to all.", "featurePowerful": "Powerful", "featurePowerfulText": "Hive is a global decentralized network. It is battle-tested by hundreds of apps, communities & projects around the world." }, diff --git a/src/app/[locale]/about/page.tsx b/src/app/[locale]/about/page.tsx index 4b581fe..4b1c9e9 100644 --- a/src/app/[locale]/about/page.tsx +++ b/src/app/[locale]/about/page.tsx @@ -5,6 +5,7 @@ import { useTranslations } from 'next-intl'; import { useRouter, usePathname } from '@/i18n/routing'; import { useAssets } from '@/hooks/useAssets'; import { ABOUT_NAVIGATION } from '@/lib/data/navigation'; +import { ABOUT_VIDEOS } from '@/lib/data/videos'; export default function AboutPage() { const router = useRouter(); @@ -12,6 +13,9 @@ export default function AboutPage() { const t = useTranslations(); const { getImage } = useAssets(); + const featuredVideo = ABOUT_VIDEOS.find(v => v.featured); + const gridVideos = ABOUT_VIDEOS.filter(v => !v.featured); + return (
@@ -59,6 +63,56 @@ export default function AboutPage() { {t('about.featurePowerfulText')}

+ + {/* Video Showcase */} +
+

+ Learn More. +
+

+ +
+ {/* Featured Video */} + {featuredVideo && ( +
+
+ +
+

{featuredVideo.title}

+

+ {featuredVideo.description} +

+
+ )} + + {/* Grid of Additional Videos */} + {gridVideos.length > 0 && ( +
+ {gridVideos.map((video) => ( +
+
+ +
+

{video.title}

+

{video.description}

+
+ ))} +
+ )} +
+
diff --git a/src/app/[locale]/core-dev-meetings/page.tsx b/src/app/[locale]/core-dev-meetings/page.tsx new file mode 100644 index 0000000..950eb9b --- /dev/null +++ b/src/app/[locale]/core-dev-meetings/page.tsx @@ -0,0 +1,90 @@ +'use client'; + +import React from 'react'; +import { useTranslations } from 'next-intl'; +import { CORE_DEV_MEETINGS } from '@/lib/data/coredevmeetings'; + +export default function CoreDevMeetingsPage() { + const t = useTranslations(); + + // Get the latest meeting (first in the array) and the next two + const latestMeeting = CORE_DEV_MEETINGS[0]; + const gridMeetings = CORE_DEV_MEETINGS.slice(1, 3); + + return ( +
+
+ {/* Hero Section */} +
+

+ Core Dev Meetings. +

+

+ Watch recordings of Hive core developer meetings to stay updated on the latest technical developments and discussions. +

+
+ + {/* Meetings Section */} +
+
+

+ Latest Meetings. +
+

+ +
+ {/* Featured Video - Latest Meeting */} + {latestMeeting && ( +
+
+ +
+

{latestMeeting.title}

+

+ The most recent core developer meeting discussing Hive blockchain development, updates, and technical decisions. +

+
+ )} + + {/* Grid of Recent Meetings */} + {gridMeetings.length > 0 && ( +
+ {gridMeetings.map((meeting) => ( +
+
+ +
+
+ ))} +
+ )} + + +
+
+
+
+
+ ); +} diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index bfa4382..8b1eae3 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -47,12 +47,15 @@ export default function HomePage() {
- +
{/* Ecosystem */} - + {/* No fees */}
diff --git a/src/components/ScrollIndicator.tsx b/src/components/ScrollIndicator.tsx index 466c109..17a0f62 100644 --- a/src/components/ScrollIndicator.tsx +++ b/src/components/ScrollIndicator.tsx @@ -2,13 +2,38 @@ import React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronDown } from '@fortawesome/free-solid-svg-icons'; -interface ScrollIndicatorProps extends React.HTMLAttributes {} +interface ScrollIndicatorProps extends React.HTMLAttributes { + scrollToSelector?: string; +} + +export const ScrollIndicator: React.FC = ({ + className, + scrollToSelector, + onClick, + ...props +}) => { + const handleClick = (e: React.MouseEvent) => { + if (scrollToSelector) { + const element = document.querySelector(scrollToSelector); + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + } + + if (onClick) { + onClick(e); + } + }; -export const ScrollIndicator: React.FC = ({ className, ...props }) => { return ( -
+
diff --git a/src/components/mobile-menu/MobileMenu.tsx b/src/components/mobile-menu/MobileMenu.tsx index 336b722..81df49b 100644 --- a/src/components/mobile-menu/MobileMenu.tsx +++ b/src/components/mobile-menu/MobileMenu.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useMainStore } from '@/store/useMainStore'; -import { Navigation } from '@/components/navigation/Navigation'; +import { MobileNavigation } from '@/components/navigation/MobileNavigation'; interface MobileMenuProps extends React.HTMLAttributes { items?: any[]; @@ -24,28 +24,32 @@ export const MobileMenu: React.FC = ({ return (
-
+ {/* Navigation overlay */} +
+ setIsMobileActive(false)} + /> +
+ + {/* Hamburger button */} +
- - - - - *]:text-center [&>*]:py-2.5 [&>*]:px-0 [&>*]:w-full -mt-[200px] bg-[#f0f0f8]`} - items={items} - onClicked={() => setIsMobileActive(false)} - />
); diff --git a/src/components/navigation/MobileNavigation.tsx b/src/components/navigation/MobileNavigation.tsx new file mode 100644 index 0000000..7570415 --- /dev/null +++ b/src/components/navigation/MobileNavigation.tsx @@ -0,0 +1,157 @@ +'use client'; + +import React, { useState } from 'react'; +import { Link } from '@/i18n/routing'; +import { ChevronDown } from 'lucide-react'; +import { Button } from '@/components/ui/button'; + +interface NavigationChild { + to?: string; + name?: string; + description?: string; +} + +interface NavigationItemType { + to?: string; + name?: string; + isButton?: boolean; + children?: NavigationChild[]; +} + +interface MobileNavigationProps { + items: NavigationItemType[]; + onClicked?: () => void; +} + +export const MobileNavigation: React.FC = ({ items, onClicked }) => { + const [openIndex, setOpenIndex] = useState(null); + + const toggleSection = (index: number) => { + setOpenIndex(openIndex === index ? null : index); + }; + + const handleLinkClick = () => { + if (onClicked) onClicked(); + }; + + const go = (url: string) => { + window.open(url, '_blank'); + if (onClicked) onClicked(); + }; + + return ( +
+ {items.map((item, index) => { + // Items with children (accordion sections) + if (item.children && item.children.length > 0) { + const isOpen = openIndex === index; + + return ( +
+ + + {isOpen && ( +
+ {item.children.map((child, childIndex) => ( +
+ {child.to && (child.to.includes('https://') || child.to.includes('mailto')) ? ( + +
+ {child.name} +
+ {child.description && ( +

+ {child.description} +

+ )} +
+ ) : child.to ? ( + +
+ {child.name} +
+ {child.description && ( +

+ {child.description} +

+ )} + + ) : null} +
+ ))} +
+ )} +
+ ); + } + + // Regular button items + if (item.isButton && item.to) { + return ( +
+ +
+ ); + } + + // Regular link items + if (item.to && (item.to.includes('https://') || item.to.includes('mailto'))) { + return ( + + ); + } + + if (item.to) { + return ( +
+ + {item.name} + +
+ ); + } + + return null; + })} +
+ ); +}; diff --git a/src/components/navigation/Navigation.tsx b/src/components/navigation/Navigation.tsx index 5eb3ca9..571e5e3 100644 --- a/src/components/navigation/Navigation.tsx +++ b/src/components/navigation/Navigation.tsx @@ -9,7 +9,6 @@ import { NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, - NavigationMenuViewport, } from '@/components/ui/navigation-menu'; import { Link } from '@/i18n/routing'; @@ -44,21 +43,24 @@ export const Navigation: React.FC = ({ return items.some(item => item.children && item.children.length > 0); }, [items]); + // Check if this is mobile menu (flex-col indicates mobile) + const isMobileMenu = className?.includes('flex-col'); + // Navigation with dropdowns if (hasDropdowns) { return ( -
- - +
+ + {items.map((item, index) => { // Dropdown menu items if (item.children && item.children.length > 0) { return ( - - + + {item.name} - +
    {item.children.map((child, childIndex) => (
  • @@ -67,6 +69,7 @@ export const Navigation: React.FC = ({ href={child.to} target="_blank" rel="nofollow noopener noreferrer" + onClick={onClicked} className="block no-underline rounded-md py-3 px-4 transition-colors duration-100 ease-in hover:bg-[#f5f5f5] focus:outline-none focus:bg-[#f5f5f5]" >
    @@ -82,6 +85,7 @@ export const Navigation: React.FC = ({
    @@ -105,7 +109,7 @@ export const Navigation: React.FC = ({ // Regular navigation items return ( - + = ({ ); })} -
    ); diff --git a/src/lib/data/coredevmeetings.ts b/src/lib/data/coredevmeetings.ts new file mode 100644 index 0000000..18e6051 --- /dev/null +++ b/src/lib/data/coredevmeetings.ts @@ -0,0 +1,58 @@ +export interface ICoreDevMeeting { + videoId: string; + title: string; + meetingNumber?: number; +} + +export const CORE_DEV_MEETINGS: ICoreDevMeeting[] = [ + { + videoId: 'tmnD5duLxcE', + title: 'Core Dev Meeting #75', + meetingNumber: 75, + }, + { + videoId: '1qPy3aR_ivo', + title: 'Core Dev Meeting #74', + meetingNumber: 74, + }, + { + videoId: 'pR-WXe1fKnA', + title: 'Core Dev Meeting #73', + meetingNumber: 73, + }, + { + videoId: 'v4FuoQK0C4s', + title: 'Core Dev Meeting #41', + meetingNumber: 41, + }, + { + videoId: 'wfvLzwnlEms', + title: 'Core Dev Meeting #40', + meetingNumber: 40, + }, + { + videoId: '1iHk9vVOAMY', + title: 'Core Dev Meeting #39', + meetingNumber: 39, + }, + { + videoId: 'ZXpzcXFPqeM', + title: 'Core Dev Meeting #38', + meetingNumber: 38, + }, + { + videoId: 'yrGrvgXAGMw', + title: 'Core Dev Meeting #37', + meetingNumber: 37, + }, + { + videoId: 'uoskscKWT-A', + title: 'Core Dev Meeting #36', + meetingNumber: 36, + }, + { + videoId: 'ikzao9_9Gl4', + title: 'Core Dev Meeting #35', + meetingNumber: 35, + }, +]; diff --git a/src/lib/data/navigation.ts b/src/lib/data/navigation.ts index 5e1f7f2..d92ec1c 100644 --- a/src/lib/data/navigation.ts +++ b/src/lib/data/navigation.ts @@ -40,6 +40,11 @@ export const NAVIGATION_HEADER_DROPDOWN = [ name: 'Repositories', description: 'Browser Hive applications and source code', }, + { + to: 'core-dev-meetings', + name: 'Core Dev Meetings', + description: 'Watch recordings of core developer meetings', + }, ], }, { diff --git a/src/lib/data/videos.ts b/src/lib/data/videos.ts new file mode 100644 index 0000000..8855a40 --- /dev/null +++ b/src/lib/data/videos.ts @@ -0,0 +1,28 @@ +export interface IVideo { + videoId: string; + title: string; + description: string; + featured?: boolean; +} + +export const ABOUT_VIDEOS: IVideo[] = [ + { + videoId: 'llIRm5XxeRA', + title: 'To Gas Or Not To Gas?', + description: + 'Gas fees shape how people experience blockchains. Some ecosystems remove them, others sponsor or hide them, and some make them so tiny they nearly disappear. This session compares four approaches.', + featured: true, + }, + { + videoId: 'cBjfIJB9XTo', + title: 'Chain Culture', + description: + 'A full day of cross-chain talks, creative showcases, penguins, and pure good vibes at HiveFest 10.', + }, + { + videoId: 'oPwuUofvf_0', + title: 'HardFork 28 - The Future of Hive', + description: + "The CoreDev team on HF28, scalability and governance behind Hive's tech engine.", + }, +]; -- GitLab