Skip to content

Commit b1689cf

Browse files
committed
Improve the project page layout.
* Refactor all styles to CSS. * Close #29.
1 parent 702666f commit b1689cf

20 files changed

+656
-150
lines changed

src/app/_hooks/useDragScroll.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { useEffect, useRef } from "react";
2+
3+
/**
4+
* Hook that enables drag-to-scroll on a horizontally scrollable element
5+
* and auto-shows/hides the scrollbar (via data-scrolling attribute).
6+
*
7+
* @returns {import("react").RefObject<HTMLElement>} ref to attach to the scrollable element
8+
*/
9+
export function useDragScroll() {
10+
const ref = useRef(null);
11+
12+
useEffect(() => {
13+
const el = ref.current;
14+
if (!el) return;
15+
16+
let isDragging = false;
17+
let startX;
18+
let scrollLeft;
19+
let scrollTimeout;
20+
21+
const onMouseDown = (e) => {
22+
isDragging = true;
23+
startX = e.pageX - el.offsetLeft;
24+
scrollLeft = el.scrollLeft;
25+
el.style.cursor = "grabbing";
26+
el.style.userSelect = "none";
27+
};
28+
29+
const onMouseMove = (e) => {
30+
if (!isDragging) return;
31+
e.preventDefault();
32+
const x = e.pageX - el.offsetLeft;
33+
el.scrollLeft = scrollLeft - (x - startX);
34+
};
35+
36+
const onMouseUp = () => {
37+
isDragging = false;
38+
el.style.cursor = "";
39+
el.style.userSelect = "";
40+
};
41+
42+
const onScroll = () => {
43+
el.setAttribute("data-scrolling", "");
44+
clearTimeout(scrollTimeout);
45+
scrollTimeout = setTimeout(() => {
46+
el.removeAttribute("data-scrolling");
47+
}, 1000);
48+
};
49+
50+
el.addEventListener("mousedown", onMouseDown);
51+
el.addEventListener("mousemove", onMouseMove);
52+
el.addEventListener("mouseup", onMouseUp);
53+
el.addEventListener("mouseleave", onMouseUp);
54+
el.addEventListener("scroll", onScroll);
55+
56+
return () => {
57+
el.removeEventListener("mousedown", onMouseDown);
58+
el.removeEventListener("mousemove", onMouseMove);
59+
el.removeEventListener("mouseup", onMouseUp);
60+
el.removeEventListener("mouseleave", onMouseUp);
61+
el.removeEventListener("scroll", onScroll);
62+
clearTimeout(scrollTimeout);
63+
};
64+
}, []);
65+
66+
return ref;
67+
}

src/app/_styles/main.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
@import "../../components/ui/timeline/timeline.css";
1212
@import "../../components/ui/steps/steps.css";
1313
@import "../(home)/home.css";
14+
@import "../projects/projects.css";
1415
@import "keen-slider/keen-slider.min.css";
1516
/* Include all styles here 👆. PostCSS will bundle this into 1 file. */
1617

src/app/projects/[project]/singleProject.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export default function SingleProject({
5050
<SingleProjectsLinks sectionType={sectionType} />
5151
<SingleProjectsBrief sectionType={sectionType} data={data} />
5252
<PageContainer noFlex noPadding sectionType={sectionType}>
53-
<hr className={`mt-6 mb-2 h-px border-0 bg-neutral-400 lg:my-6`} />
53+
<hr className="single-project-divider" />
5454
</PageContainer>
5555
{data.meta.screenshots ? (
5656
<SingleProjectsScreenshots sectionType={sectionType} data={data} />

src/app/projects/[project]/singleProjectsContribute.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ export default function SingleProjectsContribute({
1111
}) {
1212
return (
1313
<PageContainer sectionType={sectionType}>
14-
<h2 className={`sub-heading-main`}>How to Contribute</h2>
14+
<h2 className="sub-heading-main">How to Contribute</h2>
1515
<div
1616
className={`my-2 h-1 w-10 app-fill--${SectionType.invert(sectionType)}`}
1717
/>
18-
<p className={`project-paragraph my-4 lg:w-[50%]`}>
18+
<p className="single-project-contribute-text project-paragraph">
1919
Open Fresno is run by volunteers. We are always looking for help.
2020
Explore the various ways you can make a difference.
2121
</p>
22-
<h4 className={`project-info-label mb-2 font-semibold`}>
22+
<h4 className="single-project-contribute-label project-info-label">
2323
Get Involved As
2424
</h4>
25-
<div className={`flex flex-wrap gap-4`}>
25+
<div className="single-project-contribute-buttons">
2626
{Object.keys(data.meta.contributing).map((role, i) => (
2727
<Button
2828
key={role + i}

src/app/projects/[project]/singleProjectsLinks.jsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,24 @@ import Link from "next/link";
22

33
const SingleProjectsLinks = () => {
44
return (
5-
<section className={`app-color--primary px-6 py-6`}>
6-
<div
7-
className={`mx-auto flex max-w-[calc(var(--screen-xxl)+80px)] flex-col max-lg:gap-4 lg:flex-row lg:justify-between`}
8-
>
9-
<Link className={`underline`} href="#project-brief">
5+
<section className="single-project-links app-color--primary">
6+
<div className="single-project-links-container">
7+
<Link className="underline" href="#project-brief">
108
Project Brief
119
</Link>
12-
<Link className={`underline`} href="#screenshots">
10+
<Link className="underline" href="#screenshots">
1311
Screenshots
1412
</Link>
15-
<Link className={`underline`} href="#roadmap">
13+
<Link className="underline" href="#roadmap">
1614
Roadmap
1715
</Link>
18-
<Link className={`underline`} href="#how-to-contribute">
16+
<Link className="underline" href="#how-to-contribute">
1917
How to Contribute
2018
</Link>
21-
<Link className={`underline`} href="#resources">
19+
<Link className="underline" href="#resources">
2220
Resources
2321
</Link>
24-
<Link className={`underline`} href="#how-to-volunteer">
22+
<Link className="underline" href="#how-to-volunteer">
2523
How to Volunteer
2624
</Link>
2725
</div>

src/app/projects/[project]/singleProjectsResources.jsx

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,53 +14,51 @@ export default function SingleProjectsResources({
1414
} else {
1515
return (
1616
<PageContainer sectionType={sectionType}>
17-
<div
18-
className={`project-main-heading-container heading-underline underline-alt`}
19-
>
20-
<h2 className={`project-heading`}>Resources</h2>
17+
<div className="project-main-heading-container heading-underline underline-alt">
18+
<h2 className="project-heading">Resources</h2>
2119
</div>
22-
<p className={`project-paragraph`}>
20+
<p className="project-paragraph">
2321
Explore our resources section on the project page to discover a wealth
2422
of design assets, tutorials, and tools that will inspire and empower
2523
your creative journey.
2624
</p>
27-
<hr className={`project-info-line`} />
28-
<div className={`project-info-container`}>
29-
<p className={`project-info-label`}>Documentation</p>
30-
<p className={`project-info-text`}>n/a</p>
25+
<hr className="project-info-line" />
26+
<div className="project-info-container">
27+
<p className="project-info-label">Documentation</p>
28+
<p className="project-info-text">n/a</p>
3129
</div>
3230
{(() => {
3331
if (data.meta.resources.tutorials) {
3432
let tutorialCounter = 1;
3533
return data.meta.resources.tutorials.map((link) => (
3634
<>
37-
<hr className={`project-info-line`} />
38-
<div className={`project-info-container`}>
39-
<p className={`project-info-label`}>
35+
<hr className="project-info-line" />
36+
<div className="project-info-container">
37+
<p className="project-info-label">
4038
Tutorial {tutorialCounter++}
4139
</p>
42-
<Link className={`project-info-link`} key={link} href={link}>
40+
<Link className="project-info-link" key={link} href={link}>
4341
Download
4442
</Link>
4543
</div>
4644
</>
4745
));
4846
}
4947
})()}
50-
<hr className={`project-info-line`} />
48+
<hr className="project-info-line" />
5149
<div>
52-
<div className={`project-info-container`}>
53-
<p className={`project-info-label`}>Meeting Times</p>
54-
<p className={`project-info-text`}>
50+
<div className="project-info-container">
51+
<p className="project-info-label">Meeting Times</p>
52+
<p className="project-info-text">
5553
{data.meta.resources.meeting_times}
5654
</p>
57-
<p className={`project-info-label`}>Office Hours</p>
58-
<p className={`project-info-text`}>
55+
<p className="project-info-label">Office Hours</p>
56+
<p className="project-info-text">
5957
{data.meta.resources.office_hours}
6058
</p>
6159
</div>
6260
</div>
63-
<hr className={`project-info-line`} />
61+
<hr className="project-info-line" />
6462
</PageContainer>
6563
);
6664
}

src/app/projects/[project]/singleProjectsRoadmap.jsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ export default function SingleProjectsRoadmap({ data, sectionType }) {
3535

3636
return (
3737
<section className={`py-12 app-color--${sectionType}`}>
38-
<div className={`page-container flex flex-col`}>
39-
<h2 className={`sub-heading-main`}>Roadmap</h2>
38+
<div className="page-container flex flex-col">
39+
<h2 className="sub-heading-main">Roadmap</h2>
4040
<div
4141
className={`my-2 h-1 w-10 app-fill--${SectionType.invert(sectionType)}`}
4242
/>
43-
<p className={`paragraph-large project-paragraph-large mb-8 lg:mb-18`}>
43+
<p className="single-project-roadmap-subtitle paragraph-large project-paragraph-large">
4444
Know about the current progress, scope, and stage of project
4545
</p>
46-
<div className={`flex flex-col lg:my-6 lg:flex-row lg:gap-70`}>
47-
<div className={`grow basis-0`}>
48-
<div className={`lg:ml-[15%]`}>
46+
<div className="single-project-roadmap-layout">
47+
<div className="grow basis-0">
48+
<div className="lg:ml-[15%]">
4949
{milestones.map((milestone, index) => {
5050
return (
5151
<SingleProjectsRoadmapMilestone
@@ -59,19 +59,19 @@ export default function SingleProjectsRoadmap({ data, sectionType }) {
5959
})}
6060
</div>
6161
</div>
62-
<div className="project-roadmap-details-container grow basis-0 max-lg:mt-12">
62+
<div className="project-roadmap-details-container">
6363
<div>
64-
<h4 className={`project-roadmap-info-label-two`}>Objective</h4>
64+
<h4 className="project-roadmap-info-label-two">Objective</h4>
6565
<hr className="project-info-line my-2" />
6666
<p className="project-paragraph-alt mb-8">
6767
{data.meta.roadmap.objective}
6868
</p>
69-
<h4 className={`project-roadmap-info-label-two`}>Comments</h4>
69+
<h4 className="project-roadmap-info-label-two">Comments</h4>
7070
<hr className="project-info-line my-2" />
7171
<p className="project-paragraph-alt mb-8">
7272
{data.meta.roadmap.comments}
7373
</p>
74-
<h4 className={`project-roadmap-info-label-two`}>Outcome</h4>
74+
<h4 className="project-roadmap-info-label-two">Outcome</h4>
7575
<hr className="project-info-line my-2" />
7676
<p className="project-paragraph-alt">
7777
{data.meta.roadmap.outcome}

src/app/projects/[project]/singleProjectsRoadmapMilestone.jsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@ export default function SingleProjectsRoadmapMilestone({
1515
}) {
1616
return (
1717
<>
18-
<div
19-
className={`project-roadmap-info-container flex w-fit flex-row gap-4`}
20-
>
18+
<div className="project-roadmap-info-container">
2119
<Image
22-
className="project-roadmap-icon aspect-1/1 object-cover"
20+
className="project-roadmap-icon"
2321
src={
2422
data.meta.roadmap[milestone].status === "completed"
2523
? checkCircle
@@ -31,8 +29,8 @@ export default function SingleProjectsRoadmapMilestone({
3129
width={32}
3230
height={32}
3331
/>
34-
<div className={`project-info-text-container`}>
35-
<p className={`text-lg font-bold`}>{titleCase(milestone)}</p>
32+
<div className="project-info-text-container">
33+
<p className="text-lg font-bold">{titleCase(milestone)}</p>
3634
<p
3735
className={`text-base font-light ${sectionType === SectionType.dark && "text-neutral-300"}`}
3836
>
@@ -42,7 +40,7 @@ export default function SingleProjectsRoadmapMilestone({
4240
</div>
4341
{!isLastIndex && (
4442
<Image
45-
className="project-roadmap-icon-line relative -top-3 left-3.5 inline-block h-8 w-[2px] origin-bottom-left object-cover"
43+
className="project-roadmap-icon-line"
4644
src={
4745
data.meta.roadmap[milestone].status === "completed" ? line4 : line5
4846
}

src/app/projects/[project]/singleProjectsScreenshots.jsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,26 @@ export default function SingleProjectsScreenshots({
3333
for (let i = shownImages.length; i < 6; i++) {
3434
shownImages.push(
3535
<div
36-
className={`keen-slider__slide @container aspect-7/4`}
36+
className="keen-slider__slide @container aspect-7/4"
3737
key={data.full_name + i}
3838
>
39-
<div
40-
className={`size-full bg-neutral-400 @max-lg:rounded-xl @max-lg:border`}
41-
/>
39+
<div className="single-project-screenshot-placeholder @max-lg:rounded-xl @max-lg:border" />
4240
</div>,
4341
);
4442
}
4543
return (
4644
<section className={`py-12 app-color--${sectionType}`}>
47-
<div className={`page-container flex flex-col`}>
48-
<h2 className={`sub-heading-main`}>Screenshots</h2>
45+
<div className="page-container flex flex-col">
46+
<h2 className="sub-heading-main">Screenshots</h2>
4947
<div
5048
className={`my-2 h-1 w-10 app-color--${SectionType.invert(sectionType)}`}
5149
/>
52-
<p className={`paragraph-large project-paragraph lg:mb-16`}>
50+
<p className="paragraph-large project-paragraph lg:mb-16">
5351
Explore our project through screenshots, providing visual insights
5452
into its design and functionality.
5553
</p>
56-
<div className={`grid grid-cols-3 gap-4 max-lg:hidden`}>
57-
{shownImages}
58-
</div>
59-
<Slider className={"project-screenshots-slider-container lg:hidden"}>
54+
<div className="single-project-screenshots-grid">{shownImages}</div>
55+
<Slider className="project-screenshots-slider-container lg:hidden">
6056
{shownImages}
6157
</Slider>
6258
<SimpleDialog
@@ -66,9 +62,9 @@ export default function SingleProjectsScreenshots({
6662
setShowDialog(false);
6763
}}
6864
fullWidth={true}
69-
maxWidth={"lg"}
65+
maxWidth="lg"
7066
>
71-
<Slider className={"aspect-7/4 w-full"} startingSlide={startingSlide}>
67+
<Slider className="aspect-7/4 w-full" startingSlide={startingSlide}>
7268
{shownImages}
7369
</Slider>
7470
</SimpleDialog>

0 commit comments

Comments
 (0)