Skip to content

Commit 4e03837

Browse files
authored
Merge pull request #155 from codersforcauses/unifying_art_branches
Unifying art branches
2 parents 543c1f2 + ccb89c2 commit 4e03837

41 files changed

Lines changed: 1721 additions & 390 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

client/documentation/admin-dashboard/committee.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Committee Members
22

3-
URL: `/admin/game_dev/committee/add/`
3+
URL: `/admin/game_dev/committee/`
44

55
Profiles of the Committee Members of the club that are displayed on the about page `/about`.
66

client/documentation/admin-dashboard/contributors.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Models that associate a member object with another certain object as a contribut
44

55
## Game Contributor
66

7+
URL: `/admin/game_dev/gamecontributor/`
78
A model that will associate a certain member with having contributed to a certain game. A Game Contributor object will be represented under the 'Contributors' section of a game's page as the name of the member who contributed.
89

910
## Fields
@@ -18,19 +19,15 @@ A model that will associate a certain member with having contributed to a certai
1819

1920
You will see a little magnifying glass when selecting a Game and Member, click on it to see their respective table and be able choose the integer id's using the desired details. Though none of the individual fields are a primary key, the actual primary key is the unique (Game, Member) pair that each object forms.
2021

21-
2222
## Art Contributor
2323

24+
- This can be found inline inside of an art entry, e.g. `/admin/game_dev/art/1/change/`.
25+
2426
A model that will associate a certain member with having contributed to a certain artwork. An Art Contributor object will be represented under the 'Contributors' section of an artworks's page as the name of the member who contributed.
2527

2628
## Fields
2729

28-
**Art:** Required field for the artwork that the contributor is for. It is an integer field that corresponds to the raw integer id of an Art object in the Art table, known as a Foreign Key.
29-
3030
**Member:** Required field for the member that is the contributor to the specified artwork. It is an integer field that corresponds to the raw integer id of a Member object in the Member table, known as a Foreign Key.
3131

3232
**Role:** Required character field for the description of the role that the person played in contributing to the artwork. Maximum length of 100 characters
3333

34-
## Other Notes
35-
36-
You will see a little magnifying glass when selecting an Art and a Member, click on it to see their respective table and be able choose the integer id's using the desired details. Though none of the individual fields are a primary key, the actual primary key is the unique (Art, Member) pair that each object forms.

client/next.config.mjs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
// import os from "node:os";
2-
// import isInsideContainer from "is-inside-container";
3-
4-
// const isWindowsDevContainer = () =>
5-
// os.release().toLowerCase().includes("microsoft") && isInsideContainer();
6-
71
/** @type {import('next').NextConfig} */
82

9-
const config = {
3+
const nextConfig = {
104
reactStrictMode: true,
115
turbopack: {
126
root: import.meta.dirname,
@@ -27,4 +21,4 @@ const config = {
2721
// : undefined,
2822
};
2923

30-
export default config;
24+
export default nextConfig;

client/package-lock.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"react": "19.1.0",
3333
"react-dom": "19.1.0",
3434
"react-social-icons": "^6.25.0",
35+
"react-use-measure": "^2.1.7",
3536
"tailwind-merge": "^3.3.1",
3637
"tailwindcss-animate": "^1.0.7"
3738
},

client/public/placeholder-icon.svg

Lines changed: 6 additions & 0 deletions
Loading

client/scripts/open-when-ready.js

Whitespace-only changes.

client/src/components/main/Footer.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
Home,
88
Map,
99
Palette,
10-
Sparkles,
1110
Users,
1211
} from "lucide-react";
1312
import Image from "next/image";
@@ -120,7 +119,7 @@ export default function Footer() {
120119
ease: "easeInOut",
121120
}}
122121
>
123-
<Sparkles className="h-4 w-4 text-yellow-400" />
122+
<Gamepad2 className="h-5 w-5 text-yellow-400" />
124123
</motion.div>
125124
</motion.div>
126125
<div>

client/src/components/main/MemberProfile.tsx

Lines changed: 0 additions & 117 deletions
This file was deleted.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import {
2+
animate,
3+
AnimationPlaybackControls,
4+
motion,
5+
useMotionValue,
6+
} from "framer-motion";
7+
import { useCallback, useEffect, useRef } from "react";
8+
import useMeasure from "react-use-measure";
9+
10+
import ImageCard from "@/components/ui/ImageCard/ImageCard";
11+
import { Art } from "@/types/art";
12+
13+
import ImageCardBack from "./ImageCard/ImageCardBack";
14+
15+
const GAP = 16;
16+
const DURATION = 90;
17+
18+
// modifying this to accept anything with a name, src, and id should be trivial.
19+
export default function ContinuousCarousel(artworks: Art[], reverse = false) {
20+
const [ref, { width }] = useMeasure();
21+
const xTranslation = useMotionValue(0);
22+
23+
const controlsRef = useRef<AnimationPlaybackControls | null>(null);
24+
25+
const startAnimation = useCallback(
26+
(from: number) => {
27+
const finalPosition = -(width + GAP) / 3;
28+
const rangeSize = -finalPosition;
29+
30+
controlsRef.current?.stop();
31+
32+
// Normalize `from` into [finalPosition, 0) so the loop restarts cleanly
33+
const normalizedFrom = -(((-from % rangeSize) + rangeSize) % rangeSize);
34+
xTranslation.set(normalizedFrom);
35+
36+
const target = reverse ? 0 : finalPosition;
37+
const loopStart = reverse ? finalPosition : 0;
38+
39+
const startFullLoop = () => {
40+
const controls = animate(xTranslation, [loopStart, target], {
41+
ease: "linear",
42+
duration: DURATION,
43+
repeat: Infinity,
44+
repeatType: "loop",
45+
repeatDelay: 0,
46+
});
47+
controlsRef.current = controls;
48+
};
49+
50+
// if we're already at the target end, jump to loop start and begin
51+
const remaining = Math.abs(target - normalizedFrom);
52+
if (remaining < 0.5) {
53+
xTranslation.set(loopStart);
54+
startFullLoop();
55+
return;
56+
}
57+
58+
// animate the rest of this cycle, then resume full loops
59+
const partialDuration = DURATION * (remaining / rangeSize);
60+
const controls = animate(xTranslation, target, {
61+
ease: "linear",
62+
duration: partialDuration,
63+
onComplete: startFullLoop,
64+
});
65+
controlsRef.current = controls;
66+
},
67+
[xTranslation, width, reverse],
68+
);
69+
70+
useEffect(() => {
71+
startAnimation(0);
72+
return () => {
73+
controlsRef.current?.stop();
74+
};
75+
}, [startAnimation]);
76+
77+
const items = artworks ?? [];
78+
return (
79+
<div className="overflow-hidden py-10">
80+
<motion.div
81+
className="flex w-max cursor-grab select-none gap-[16px] active:cursor-grabbing"
82+
ref={ref}
83+
style={{ x: xTranslation }}
84+
// i'm not sure how to make these have momentum.. future TODO?
85+
onPanStart={() => controlsRef.current?.stop()}
86+
onPan={(_, info) => {
87+
const rangeSize = (width + GAP) / 3;
88+
const next = xTranslation.get() + info.delta.x;
89+
const normalized = -(((-next % rangeSize) + rangeSize) % rangeSize);
90+
xTranslation.set(normalized);
91+
}}
92+
onHoverEnd={() => startAnimation(xTranslation.get())}
93+
>
94+
{/* we need three copies to make sure it doesn't randomly snap incorrectly... issues may arise on huge display resolutions */}
95+
{[...items, ...items, ...items].map((item: Art, i: number) => (
96+
<motion.div
97+
key={`${item.art_id} - ${i}`}
98+
style={{ transform: "translateZ(0)" }}
99+
whileHover={{
100+
scale: 1.05,
101+
zIndex: 1,
102+
}}
103+
transition={{ type: "spring", stiffness: 300, damping: 20 }}
104+
>
105+
<ImageCard
106+
imageSrc={item.media || undefined}
107+
imageAlt={item.name}
108+
href={`/artwork/${item.art_id}`}
109+
backContent={<ImageCardBack artwork={item} />}
110+
/>
111+
</motion.div>
112+
))}
113+
</motion.div>
114+
</div>
115+
);
116+
}

0 commit comments

Comments
 (0)