From a5348caaa042595b41c1f0574c85914756168461 Mon Sep 17 00:00:00 2001 From: Ananya Joys Date: Mon, 18 May 2026 14:27:41 +0530 Subject: [PATCH] feat: add reaing progress bar --- web/package-lock.json | 12 ------- web/src/app/agora/[id]/page.tsx | 5 ++- web/src/app/agora/page.tsx | 4 ++- web/src/app/layout.tsx | 1 + web/src/components/ReadingProgressBar.tsx | 38 +++++++++++++++++++++++ 5 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 web/src/components/ReadingProgressBar.tsx diff --git a/web/package-lock.json b/web/package-lock.json index 33c6ae4..8e42f07 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -72,7 +72,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -1589,7 +1588,6 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1656,7 +1654,6 @@ "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.58.0", "@typescript-eslint/types": "8.58.0", @@ -2182,7 +2179,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2536,7 +2532,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -3166,7 +3161,6 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3352,7 +3346,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -5654,7 +5647,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -5664,7 +5656,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -6413,7 +6404,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -6576,7 +6566,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6862,7 +6851,6 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/web/src/app/agora/[id]/page.tsx b/web/src/app/agora/[id]/page.tsx index f2b4c27..d557138 100644 --- a/web/src/app/agora/[id]/page.tsx +++ b/web/src/app/agora/[id]/page.tsx @@ -1,5 +1,5 @@ "use client"; - +import ReadingProgressBar from "@/components/ReadingProgressBar"; import { useEffect, useState } from "react"; import Link from "next/link"; import { useParams } from "next/navigation"; @@ -111,6 +111,8 @@ export default function AgoraDraftDetailPage() { } return ( + <> +
{/* Back link */} @@ -198,6 +200,7 @@ export default function AgoraDraftDetailPage() { )}
+ ); } diff --git a/web/src/app/agora/page.tsx b/web/src/app/agora/page.tsx index b40c9be..108afc2 100644 --- a/web/src/app/agora/page.tsx +++ b/web/src/app/agora/page.tsx @@ -1,5 +1,5 @@ "use client"; - +import ReadingProgressBar from "@/components/ReadingProgressBar"; import { useEffect, useState } from "react"; import { motion } from "framer-motion"; import { MainLayout } from "@/components/layout/MainLayout"; @@ -99,6 +99,7 @@ export default function AgoraPage() { }; return ( + {/* Page Header */} @@ -252,5 +253,6 @@ export default function AgoraPage() { + ); } diff --git a/web/src/app/layout.tsx b/web/src/app/layout.tsx index 95b516b..1eaf910 100644 --- a/web/src/app/layout.tsx +++ b/web/src/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import "./globals.css"; import { AmbientBackground } from "@/components/layout/AmbientBackground"; + export const metadata: Metadata = { title: "Writers' Pub — A Premium Ecosystem for Creative Minds", description: "Connect writers, editors, and publishers in a structured ecosystem for writing, feedback, and publishing.", diff --git a/web/src/components/ReadingProgressBar.tsx b/web/src/components/ReadingProgressBar.tsx new file mode 100644 index 0000000..40674e7 --- /dev/null +++ b/web/src/components/ReadingProgressBar.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { motion, useSpring } from "framer-motion"; + +const ReadingProgressBar = () => { + const [progress, setProgress] = useState(0); + + const spring = useSpring(progress, { + stiffness: 200, + damping: 30, + }); + + useEffect(() => { + const updateProgress = () => { + const scrollTop = window.scrollY; + const docHeight = + document.documentElement.scrollHeight - window.innerHeight; + const percent = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0; + setProgress(percent); + spring.set(percent); + }; + + window.addEventListener("scroll", updateProgress, { passive: true }); + return () => window.removeEventListener("scroll", updateProgress); + }, [spring]); + + return ( +
+ +
+ ); +}; + +export default ReadingProgressBar; \ No newline at end of file