-
Notifications
You must be signed in to change notification settings - Fork 14
feat(footer): expand footer with AOSSIE info and multi-column layout #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -93,38 +93,51 @@ interface FAQItemProps { | |||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| function FAQItem({ question, answer, isOpen, onClick, index, icon }: FAQItemProps) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const contentRef = useRef<HTMLDivElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||
| const [hovered, setHovered] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <motion.div | ||||||||||||||||||||||||||||||||||||||||||||||
| className={`rounded-xl overflow-hidden transition-all duration-300 | ||||||||||||||||||||||||||||||||||||||||||||||
| bg-white dark:bg-black | ||||||||||||||||||||||||||||||||||||||||||||||
| border | ||||||||||||||||||||||||||||||||||||||||||||||
| ${isOpen | ||||||||||||||||||||||||||||||||||||||||||||||
| ? 'border- 6 border-pink-500 dark:border-grey-500' | ||||||||||||||||||||||||||||||||||||||||||||||
| : 'border- 6 - dark:border-grey-500'} | ||||||||||||||||||||||||||||||||||||||||||||||
| `} | ||||||||||||||||||||||||||||||||||||||||||||||
| bg-white dark:bg-black border | ||||||||||||||||||||||||||||||||||||||||||||||
| ${isOpen | ||||||||||||||||||||||||||||||||||||||||||||||
| ? 'border-pink-500 dark:border-grey-500' | ||||||||||||||||||||||||||||||||||||||||||||||
| : 'dark:border-grey-500'} | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+101
to
+104
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# First, check the specific file and lines mentioned
echo "=== Content at src/Pages/FaqPage/FAQ.tsx lines 101-104 ==="
if [ -f "src/Pages/FaqPage/FAQ.tsx" ]; then
sed -n '95,110p' "src/Pages/FaqPage/FAQ.tsx"
else
echo "File not found"
fi
# Check for "grey" token usage in the file
echo -e "\n=== Occurrences of 'grey' in FAQ.tsx ==="
rg -n 'grey' "src/Pages/FaqPage/FAQ.tsx" || echo "No matches found"
# Check for Tailwind config files
echo -e "\n=== Tailwind configuration files ==="
fd 'tailwind\.config\.(js|ts|cjs|mjs)$' -x sh -c 'echo "--- File: {} ---"; cat "{}"' || echo "No Tailwind config found"Repository: AOSSIE-Org/PictoPy-Website Length of output: 2281 Change Lines 103 and 104 use Suggested fix- ? 'border-pink-500 dark:border-grey-500'
- : 'dark:border-grey-500'}
+ ? 'border-pink-500 dark:border-gray-500'
+ : 'dark:border-gray-500'}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| `} | ||||||||||||||||||||||||||||||||||||||||||||||
| initial={{ opacity: 0, y: 30 }} | ||||||||||||||||||||||||||||||||||||||||||||||
| whileInView={{ opacity: 1, y: 0 }} | ||||||||||||||||||||||||||||||||||||||||||||||
| transition={{ duration: 0.5, delay: index * 0.1 }} | ||||||||||||||||||||||||||||||||||||||||||||||
| viewport={{ once: true }} | ||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||||||||||||||
| className="flex justify-between items-center w-full text-left p-6 group" | ||||||||||||||||||||||||||||||||||||||||||||||
| className={`flex justify-between items-center w-full text-left p-6 group | ||||||||||||||||||||||||||||||||||||||||||||||
| transition-colors duration-300 rounded-xl | ||||||||||||||||||||||||||||||||||||||||||||||
| ${hovered && !isOpen ? 'bg-green-50 dark:bg-green-900/10' : ''} | ||||||||||||||||||||||||||||||||||||||||||||||
| `} | ||||||||||||||||||||||||||||||||||||||||||||||
| onClick={onClick} | ||||||||||||||||||||||||||||||||||||||||||||||
| onMouseEnter={() => setHovered(true)} | ||||||||||||||||||||||||||||||||||||||||||||||
| onMouseLeave={() => setHovered(false)} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
| onMouseLeave={() => setHovered(false)} | |
| onMouseLeave={() => setHovered(false)} | |
| onFocus={() => setHovered(true)} | |
| onBlur={() => setHovered(false)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set an explicit button type on the FAQ toggle.
Line [111] should declare type="button" to prevent implicit form submission behavior.
Suggested fix
<button
+ type="button"
className={`flex justify-between items-center w-full text-left p-6 group📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button | |
| className="flex justify-between items-center w-full text-left p-6 group" | |
| className={`flex justify-between items-center w-full text-left p-6 group | |
| transition-colors duration-300 rounded-xl | |
| ${hovered && !isOpen ? 'bg-green-50 dark:bg-green-900/10' : ''} | |
| `} | |
| onClick={onClick} | |
| onMouseEnter={() => setHovered(true)} | |
| onMouseLeave={() => setHovered(false)} | |
| aria-expanded={isOpen} | |
| > | |
| <button | |
| type="button" | |
| className={`flex justify-between items-center w-full text-left p-6 group | |
| transition-colors duration-300 rounded-xl | |
| ${hovered && !isOpen ? 'bg-green-50 dark:bg-green-900/10' : ''} | |
| `} | |
| onClick={onClick} | |
| onMouseEnter={() => setHovered(true)} | |
| onMouseLeave={() => setHovered(false)} | |
| aria-expanded={isOpen} | |
| > |
🧰 Tools
🪛 Biome (2.4.4)
[error] 111-120: Provide an explicit type prop for the button element.
(lint/a11y/useButtonType)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/Pages/FaqPage/FAQ.tsx` around lines 111 - 120, The FAQ toggle button
element (the JSX <button> with props onClick, onMouseEnter, onMouseLeave,
aria-expanded) currently lacks an explicit type and may implicitly submit
surrounding forms; add type="button" to that button element so it does not
trigger form submission, keeping all existing props (className, onClick,
onMouseEnter, onMouseLeave, aria-expanded) intact.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,38 +1,218 @@ | ||||||
| import type React from "react" | ||||||
| import { FaDiscord } from 'react-icons/fa' // Import Discord icon from React Icons | ||||||
| import type React from "react"; | ||||||
| import { motion } from "framer-motion"; | ||||||
| import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa"; | ||||||
| import { ExternalLink } from "lucide-react"; | ||||||
|
|
||||||
| const fadeUp = { | ||||||
| hidden: { opacity: 0, y: 20 }, | ||||||
| visible: (i: number) => ({ | ||||||
| opacity: 1, | ||||||
| y: 0, | ||||||
| transition: { duration: 0.5, delay: i * 0.1 }, | ||||||
| }), | ||||||
| }; | ||||||
|
|
||||||
| const Footer: React.FC = () => { | ||||||
| const year = new Date().getFullYear(); | ||||||
|
|
||||||
| return ( | ||||||
| <footer className="relative bg-white dark:bg-black text-black dark:text-white py-8 overflow-hidden border-t border-black dark:border-white transition-colors duration-300"> | ||||||
| <div className="relative container mx-auto px-6"> | ||||||
| <div className="flex justify-between items-center"> | ||||||
| {/* Left-aligned PictoPy text */} | ||||||
| <div className="flex items-center space-x-2"> | ||||||
| <p className="text-xl font-medium text-transparent bg-clip-text bg-gradient-to-r from-yellow-400 to-green-400 hover:scale-105 transition-all duration-300 ease-in-out"> | ||||||
| <footer className="bg-white dark:bg-black text-gray-700 dark:text-gray-300 border-t border-gray-200 dark:border-gray-800 transition-colors duration-300"> | ||||||
| {/* Main grid */} | ||||||
| <div className="container mx-auto px-6 py-16"> | ||||||
| <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-12"> | ||||||
| {/* Column 1 — PictoPy brand */} | ||||||
| <motion.div | ||||||
| custom={0} | ||||||
| initial="hidden" | ||||||
| whileInView="visible" | ||||||
| viewport={{ once: true }} | ||||||
| variants={fadeUp} | ||||||
| > | ||||||
| <h3 className="text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-yellow-500 to-green-500 mb-3"> | ||||||
| PictoPy | ||||||
| </h3> | ||||||
| <p className="text-sm leading-relaxed mb-4"> | ||||||
| A privacy-first, AI-powered desktop gallery application built with | ||||||
| Tauri, React, and Rust — keeping your data entirely on your | ||||||
| device. | ||||||
| </p> | ||||||
| </div> | ||||||
|
|
||||||
| {/* Right-aligned Discord Icon and "Made with love" text */} | ||||||
| <div className="flex items-center space-x-2"> | ||||||
| <a | ||||||
| href="https://discord.com/channels/1022871757289422898/1311271974630330388" | ||||||
| target="_blank" | ||||||
| rel="noopener noreferrer" | ||||||
| className="text-sm font-medium text-transparent bg-clip-text bg-gradient-to-r from-yellow-400 to-green-400 hover:bg-gradient-to-r hover:from-yellow-500 hover:to-green-500 transition duration-300 ease-in-out" | ||||||
| <a | ||||||
| href="https://github.com/AOSSIE-Org/PictoPy" | ||||||
| target="_blank" | ||||||
| rel="noopener noreferrer" | ||||||
| className="inline-flex items-center gap-1.5 text-sm font-medium text-yellow-500 hover:text-green-500 transition-colors duration-200" | ||||||
| > | ||||||
| <FaDiscord className="inline-block mr-2 text-yellow-400 hover:text-green-400 transition duration-300 ease-in-out transform scale-150" /> {/* Scale it to 1.5x */} | ||||||
| <span>Made with love by AOSSIE team</span> | ||||||
| <FaGithub className="text-base" /> | ||||||
| View on GitHub | ||||||
| <ExternalLink className="w-3 h-3" /> | ||||||
| </a> | ||||||
| </div> | ||||||
| </motion.div> | ||||||
|
|
||||||
| {/* Column 2 — About AOSSIE */} | ||||||
| <motion.div | ||||||
| custom={1} | ||||||
| initial="hidden" | ||||||
| whileInView="visible" | ||||||
| viewport={{ once: true }} | ||||||
| variants={fadeUp} | ||||||
| className="lg:col-span-1" | ||||||
| > | ||||||
| <h4 className="text-sm font-semibold uppercase tracking-wider text-gray-900 dark:text-white mb-3"> | ||||||
| About AOSSIE | ||||||
| </h4> | ||||||
| <p className="text-sm leading-relaxed mb-3"> | ||||||
| <span className="font-semibold text-gray-900 dark:text-white"> | ||||||
| Australian Open Source Software Innovation and Education | ||||||
| (AOSSIE) | ||||||
| </span>{" "} | ||||||
| is an Australian not-for-profit umbrella organisation for | ||||||
| open-source projects. AOSSIE mentors students and contributors | ||||||
| through programs like Google Summer of Code and Outreachy, | ||||||
| fostering innovation in open-source software across the globe. | ||||||
| </p> | ||||||
| <a | ||||||
| href="https://aossie.org" | ||||||
| target="_blank" | ||||||
| rel="noopener noreferrer" | ||||||
| className="inline-flex items-center gap-1.5 text-sm font-medium text-yellow-500 hover:text-green-500 transition-colors duration-200" | ||||||
| > | ||||||
| aossie.org | ||||||
| <ExternalLink className="w-3 h-3" /> | ||||||
| </a> | ||||||
| </motion.div> | ||||||
|
|
||||||
| {/* Column 3 — Quick Links */} | ||||||
| <motion.div | ||||||
| custom={2} | ||||||
| initial="hidden" | ||||||
| whileInView="visible" | ||||||
| viewport={{ once: true }} | ||||||
| variants={fadeUp} | ||||||
| > | ||||||
| <h4 className="text-sm font-semibold uppercase tracking-wider text-gray-900 dark:text-white mb-3"> | ||||||
| Quick Links | ||||||
| </h4> | ||||||
| <ul className="space-y-2 text-sm"> | ||||||
| {[ | ||||||
| { | ||||||
| label: "Documentation", | ||||||
| href: "https://aossie-org.github.io/PictoPy/", | ||||||
| }, | ||||||
| { | ||||||
| label: "Releases", | ||||||
| href: "https://github.com/AOSSIE-Org/PictoPy/releases", | ||||||
| }, | ||||||
| { | ||||||
| label: "Issue Tracker", | ||||||
| href: "https://github.com/AOSSIE-Org/PictoPy/issues", | ||||||
| }, | ||||||
| { | ||||||
| label: "Contributing Guide", | ||||||
| href: "https://github.com/AOSSIE-Org/PictoPy/blob/main/CONTRIBUTING.md", | ||||||
| }, | ||||||
| { | ||||||
| label: "AOSSIE Projects", | ||||||
| href: "https://aossie.org/#projects", | ||||||
| }, | ||||||
| { | ||||||
| label: "Google Summer of Code", | ||||||
| href: "https://summerofcode.withgoogle.com/", | ||||||
| }, | ||||||
| ].map(({ label, href }) => ( | ||||||
| <li key={label}> | ||||||
| <a | ||||||
| href={href} | ||||||
| target="_blank" | ||||||
| rel="noopener noreferrer" | ||||||
| className="hover:text-yellow-500 dark:hover:text-green-400 transition-colors duration-200" | ||||||
| > | ||||||
| {label} | ||||||
| </a> | ||||||
| </li> | ||||||
| ))} | ||||||
| </ul> | ||||||
| </motion.div> | ||||||
|
|
||||||
| {/* Column 4 — Community */} | ||||||
| <motion.div | ||||||
| custom={3} | ||||||
| initial="hidden" | ||||||
| whileInView="visible" | ||||||
| viewport={{ once: true }} | ||||||
| variants={fadeUp} | ||||||
| > | ||||||
| <h4 className="text-sm font-semibold uppercase tracking-wider text-gray-900 dark:text-white mb-3"> | ||||||
| Community | ||||||
| </h4> | ||||||
| <p className="text-sm leading-relaxed mb-4"> | ||||||
| Join our community to report bugs, request features, chat with | ||||||
| contributors, and follow AOSSIE's open-source journey. | ||||||
| </p> | ||||||
| <div className="flex flex-col gap-3"> | ||||||
| <a | ||||||
| href="https://discord.com/channels/1022871757289422898/1311271974630330388" | ||||||
| target="_blank" | ||||||
| rel="noopener noreferrer" | ||||||
| className="inline-flex items-center gap-2 text-sm font-medium hover:text-yellow-500 dark:hover:text-green-400 transition-colors duration-200" | ||||||
| > | ||||||
| <FaDiscord className="text-lg text-indigo-500" /> | ||||||
| Discord Server | ||||||
| </a> | ||||||
|
Comment on lines
+153
to
+160
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a public Discord invite URL instead of a channel deep-link. Line [153] links to a specific Discord channel route, which usually fails for users who are not already in the server. Use a server invite ( Suggested fix- href="https://discord.com/channels/1022871757289422898/1311271974630330388"
+ href="https://discord.gg/<your-invite-code>"🤖 Prompt for AI Agents |
||||||
| <a | ||||||
| href="https://github.com/AOSSIE-Org" | ||||||
| target="_blank" | ||||||
| rel="noopener noreferrer" | ||||||
| className="inline-flex items-center gap-2 text-sm font-medium hover:text-yellow-500 dark:hover:text-green-400 transition-colors duration-200" | ||||||
| > | ||||||
| <FaGithub className="text-lg" /> | ||||||
| AOSSIE on GitHub | ||||||
| </a> | ||||||
| <a | ||||||
| href="https://twitter.com/aossie_org" | ||||||
| target="_blank" | ||||||
| rel="noopener noreferrer" | ||||||
| className="inline-flex items-center gap-2 text-sm font-medium hover:text-yellow-500 dark:hover:text-green-400 transition-colors duration-200" | ||||||
| > | ||||||
| <FaTwitter className="text-lg text-sky-500" /> | ||||||
| @aossie_org | ||||||
| </a> | ||||||
| </div> | ||||||
| </motion.div> | ||||||
| </div> | ||||||
| </div> | ||||||
|
|
||||||
| <div className="mt-4 text-center border-t border-white pt-2"> | ||||||
| {/* You can add any content here if needed */} | ||||||
| {/* Bottom bar */} | ||||||
| <div className="border-t border-gray-200 dark:border-gray-800"> | ||||||
| <div className="container mx-auto px-6 py-5 flex flex-col sm:flex-row items-center justify-between gap-3 text-xs text-gray-500 dark:text-gray-500"> | ||||||
| <p> | ||||||
| {`© ${year} `} | ||||||
| <a | ||||||
| href="https://aossie.org" | ||||||
| target="_blank" | ||||||
| rel="noopener noreferrer" | ||||||
| className="hover:text-yellow-500 transition-colors duration-200" | ||||||
| > | ||||||
| {"AOSSIE"} | ||||||
| </a> | ||||||
| { | ||||||
| ". PictoPy is open-source software released under the MIT License." | ||||||
|
||||||
| ". PictoPy is open-source software released under the MIT License." | |
| ". PictoPy is open-source software licensed under the terms described in the project's LICENSE file." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Externalize footer copy to localization resources.
Most newly added user-facing strings are hardcoded in JSX (headings, descriptions, labels, bottom bar). Move them to i18n resource files.
Suggested direction
- <h4 className="...">About AOSSIE</h4>
+ <h4 className="...">{t("footer.about.title")}</h4>
- <p className="text-sm leading-relaxed mb-4">
- Join our community to report bugs, request features...
- </p>
+ <p className="text-sm leading-relaxed mb-4">
+ {t("footer.community.description")}
+ </p>As per coding guidelines Internationalization: User-visible strings should be externalized to resource files (i18n).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/Pages/Footer/Footer.tsx` around lines 31 - 211, The Footer component
currently contains many hardcoded user-facing strings (e.g., headings "PictoPy",
"About AOSSIE", "Quick Links", "Community", link labels, description paragraph,
bottom bar copy and "Made with ♥ by the AOSSIE Team") — replace each literal
with i18n lookup keys (e.g., t('footer.title'), t('footer.description'),
t('footer.about.heading'), t('footer.quickLinks.docs'),
t('footer.bottom.copyright'), t('footer.madeBy')) by importing and using your
i18n hook (e.g., useTranslation or t) at the top of the Footer component, add
corresponding keys into the locale resource files for supported languages, and
keep the existing JSX structure/props (FaGithub, motion.div, year variable, link
hrefs) intact so only string values change; ensure pluralization/fallbacks as
needed and update tests or snapshots that assert exact text if present.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The border color classes here look incorrect/incomplete:
dark:border-grey-500usesgrey(not in Tailwind’s default palette, and not defined in this repo’s Tailwind config), so it won’t apply.currentColorborder (often too dark/unintended).Use
dark:border-gray-*and also set an explicit light-mode border color (e.g.,border-gray-200) for the non-open state to match the rest of the UI.