Implement unified scroll to download section

This commit is contained in:
2026-03-19 15:03:45 +03:00
Unverified
parent da76f9df74
commit 9588f36f6a
4 changed files with 73 additions and 11 deletions
+11 -3
View File
@@ -3,7 +3,11 @@ import { MaterialIcon } from "@/utils/material";
import { GitHubLink, GITHUB_WEB, GITHUB_APP, GITHUB_LICENSE } from "@/pages/home/homeLinks"; import { GitHubLink, GITHUB_WEB, GITHUB_APP, GITHUB_LICENSE } from "@/pages/home/homeLinks";
import styles from "@/pages/home/home-footer.module.scss"; import styles from "@/pages/home/home-footer.module.scss";
export function HomeFooter() { interface HomeFooterProps {
onScrollToDownload?: () => void;
}
export function HomeFooter({ onScrollToDownload }: HomeFooterProps) {
return ( return (
<footer className={styles.homepageFooter}> <footer className={styles.homepageFooter}>
<div className={styles.footerBrand}> <div className={styles.footerBrand}>
@@ -15,10 +19,14 @@ export function HomeFooter() {
</div> </div>
<div className={styles.footerLinks}> <div className={styles.footerLinks}>
<div className={styles.footerSection}> <div className={styles.footerSection}>
<Link to="/#download" className={styles.footerLink}> <button
type="button"
onClick={onScrollToDownload}
className={styles.footerLink}
>
<MaterialIcon name="download" className={styles.footerLinkIcon} /> <MaterialIcon name="download" className={styles.footerLinkIcon} />
Скачать приложение Скачать приложение
</Link> </button>
<Link to="/login" className={styles.footerLink}> <Link to="/login" className={styles.footerLink}>
<MaterialIcon name="language" className={styles.footerLinkIcon} /> <MaterialIcon name="language" className={styles.footerLinkIcon} />
Веб-версия Веб-версия
+12 -4
View File
@@ -5,15 +5,23 @@ import { MaterialButton, MaterialIconButton } from "@/utils/material";
import { GitHubLink, SupportLink } from "@/pages/home/homeLinks"; import { GitHubLink, SupportLink } from "@/pages/home/homeLinks";
import styles from "@/pages/home/home-header.module.scss"; import styles from "@/pages/home/home-header.module.scss";
export function HomeHeader() { interface HomeHeaderProps {
onScrollToDownload?: () => void;
}
export function HomeHeader({ onScrollToDownload }: HomeHeaderProps) {
const navigate = useNavigate(); const navigate = useNavigate();
const { user } = useUserStore(); const { user } = useUserStore();
const { isMobile } = useDownloadAppScreen(); const { isMobile } = useDownloadAppScreen();
const isLoggedIn = user.authToken && user.currentUser; const isLoggedIn = user.authToken && user.currentUser;
const handleMobileDownload = () => {
onScrollToDownload?.();
};
function handleGetStarted() { function handleGetStarted() {
if (isMobile) { if (isMobile) {
navigate("/download-app"); handleMobileDownload();
} else if (isLoggedIn) { } else if (isLoggedIn) {
navigate("/chat"); navigate("/chat");
} else { } else {
@@ -35,7 +43,7 @@ export function HomeHeader() {
); );
return ( return (
<header className={styles.homepageHeader}> <header className={styles.homepageHeader} data-home-header>
<div className={styles.headerInner}> <div className={styles.headerInner}>
<div className={styles.headerContent}> <div className={styles.headerContent}>
<div className={styles.logo}> <div className={styles.logo}>
@@ -55,7 +63,7 @@ export function HomeHeader() {
{isMobile ? ( {isMobile ? (
<MaterialIconButton <MaterialIconButton
variant="filled" variant="filled"
onClick={() => navigate("/download-app")} onClick={handleMobileDownload}
icon="download" icon="download"
className={styles.headerSmallButton} className={styles.headerSmallButton}
/> />
+14 -4
View File
@@ -1,5 +1,5 @@
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useState, type ReactNode } from "react"; import { useRef, useState, type ReactNode } from "react";
import styles from "@/pages/home/home.module.scss"; import styles from "@/pages/home/home.module.scss";
import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen"; import useDownloadAppScreen from "@/core/hooks/useDownloadAppScreen";
import { MaterialButton, MaterialIcon, MaterialIconButton, MaterialList, MaterialListItem } from "@/utils/material"; import { MaterialButton, MaterialIcon, MaterialIconButton, MaterialList, MaterialListItem } from "@/utils/material";
@@ -55,6 +55,16 @@ export default function HomePage() {
const [dialogOpen, setDialogOpen] = useState(false); const [dialogOpen, setDialogOpen] = useState(false);
const [dialogOs, setDialogOs] = useState<DownloadOs>(() => detectOs()); const [dialogOs, setDialogOs] = useState<DownloadOs>(() => detectOs());
const [menuOpen, setMenuOpen] = useState(false); const [menuOpen, setMenuOpen] = useState(false);
const downloadSectionRef = useRef<HTMLElement>(null);
const scrollToDownload = () => {
const section = downloadSectionRef.current;
const header = document.querySelector<HTMLElement>("[data-home-header]");
if (!section) return;
const headerHeight = header?.getBoundingClientRect().height ?? 0;
const targetY = section.getBoundingClientRect().top + window.scrollY - headerHeight;
window.scrollTo({ top: targetY, behavior: "smooth" });
};
const triggerDownload = (os: DownloadOs): boolean => { const triggerDownload = (os: DownloadOs): boolean => {
if (typeof document === "undefined") { if (typeof document === "undefined") {
@@ -84,7 +94,7 @@ export default function HomePage() {
return ( return (
<div className={styles.homepage}> <div className={styles.homepage}>
<HomeHeader /> <HomeHeader onScrollToDownload={scrollToDownload} />
<main> <main>
<section className={styles.title}> <section className={styles.title}>
@@ -156,7 +166,7 @@ export default function HomePage() {
</FeatureSection> </FeatureSection>
</section> </section>
<section id="download" className={styles.download}> <section ref={downloadSectionRef} className={styles.download}>
<div className={styles.container}> <div className={styles.container}>
<div className={styles.downloadContent}> <div className={styles.downloadContent}>
<h3>Скачайте приложение</h3> <h3>Скачайте приложение</h3>
@@ -259,7 +269,7 @@ export default function HomePage() {
</main> </main>
<DownloadDialog open={dialogOpen} onOpenChange={setDialogOpen} os={dialogOs} /> <DownloadDialog open={dialogOpen} onOpenChange={setDialogOpen} os={dialogOs} />
<HomeFooter /> <HomeFooter onScrollToDownload={scrollToDownload} />
</div> </div>
); );
} }
@@ -79,6 +79,11 @@
color: $color-dark-on-surface-variant; color: $color-dark-on-surface-variant;
text-decoration: none; text-decoration: none;
font-size: 15px; font-size: 15px;
background: none;
border: none;
padding: 0;
cursor: pointer;
font-family: inherit;
transition: color 0.2s ease, transform 0.15s ease; transition: color 0.2s ease, transform 0.15s ease;
-webkit-user-drag: none; -webkit-user-drag: none;
user-select: none; user-select: none;
@@ -86,6 +91,37 @@
&:hover { &:hover {
color: $color-dark-on-surface; color: $color-dark-on-surface;
} }
}
button.footerLink {
background: none;
border: none;
padding: 0;
cursor: pointer;
font: inherit;
}
button.footerLink {
background: none;
border: none;
padding: 0;
cursor: pointer;
font: inherit;
}
button.footerLink {
background: none;
border: none;
padding: 0;
cursor: pointer;
&:is(button) {
background: none;
border: none;
padding: 0;
cursor: pointer;
font: inherit;
}
&:active { &:active {
transform: scale(0.92); transform: scale(0.92);