diff --git a/messages/en.json b/messages/en.json index 403ec079fe2536ac90fa71d2a999689ab07434dc..a4521db188472ac0989d92a25250efea8de822ce 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 4b581fe1aa1c6713048e20b27d4f507a76b744c9..4b1c9e9a3ef03a4e37aeb7b5bd6dd5b3149122d6 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 0000000000000000000000000000000000000000..950eb9b4e83ab80accae4e6dbec3ef638d748395 --- /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 bfa43829359f87a8c10bc655ecf8ceab2878f80f..8b1eae33ef7de179826e6eff01225b21baf836f6 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 466c109e60065b71d53b8d3c735c010e3b688815..17a0f628de87cbc884b8387cf02704c09411744f 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 336b72294419d704f23a8857de512437fd20f125..81df49be717fe39cccac589ce84d99561d52349a 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 0000000000000000000000000000000000000000..75704155960e8ba203b725bf7bf7ddc40b21061d --- /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 5eb3ca94a0d2fa95ab98ed7ccc94dc76c6fd11ef..571e5e35a829c7f95ac7b6e3fb71ffe14f763ff2 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 0000000000000000000000000000000000000000..18e60515e6d554fb9b069c3b69d47272e1620d9d --- /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 5e1f7f24e521340425ab7f122240c9bafd4bcd6b..d92ec1c5a79dab3b4c5d08545c6070b7866774a7 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 0000000000000000000000000000000000000000..8855a40efbbed704a072645d71386eed6a50db9a --- /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.", + }, +];