Compare commits

...

3 commits

Author SHA1 Message Date
Nathan Lamy
2208b868c6 feat: add vite pwa plugin
All checks were successful
Deploy to Netlify / Deploy to Netlify (push) Successful in 1m36s
2025-07-30 18:57:06 +02:00
Nathan Lamy
a80b64dc4a ui: fix sonner theme 2025-07-30 18:45:17 +02:00
Nathan Lamy
4eadd2f195 chore: remove scroll restoration 2025-07-30 18:33:18 +02:00
11 changed files with 2556 additions and 84 deletions

View file

@ -127,3 +127,11 @@ html,
body {
@apply w-full h-full;
}
[data-sonner-toast][data-styled='true'] [data-description] {
color: var(--primary) !important;
}
[data-sonner-toaster][data-sonner-theme='dark'] [data-description] {
color: var(--primary) !important;
}

View file

@ -1,7 +1,7 @@
import type React from "react";
import type { Colle } from "~/lib/api";
import { Link, useNavigate } from "react-router";
import { Link } from "react-router";
import {
Card,
CardContent,
@ -26,26 +26,14 @@ const getSubjectEmoji = (_: string) => {
type ColleCardProps = {
colle: Colle;
onToggleFavorite: (id: number, favorite: boolean) => void;
beforeClick: () => void;
isFavorite: boolean;
};
export default function ColleCard({
colle,
onToggleFavorite,
beforeClick,
isFavorite,
}: ColleCardProps) {
const navigate = useNavigate();
// TODO: Remove this if scroll restoration is not needed (test first)
const handleCardClick = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
beforeClick();
setTimeout(() => navigate(`/colles/${colle.id}`), 100);
};
// TODO: Favorites
const handleToggleFavorite = (e: React.MouseEvent) => {
e.stopPropagation(); // Prevent card click
@ -58,7 +46,7 @@ export default function ColleCard({
const subjectEmoji = getSubjectEmoji(colle.subject.name);
return (
<Link to={`/colles/${colle.id}`} onClick={handleCardClick}>
<Link to={`/colles/${colle.id}`}>
<Card
id={`colle-${colle.id}`}
className="h-full cursor-pointer hover:shadow-md transition-shadow border-primary"
@ -94,7 +82,7 @@ export default function ColleCard({
)}
</CardHeader>
<CardContent className="pb-0 pt-0 px-4" onClick={handleCardClick}>
<CardContent className="pb-0 pt-0 px-4">
<div className="flex items-center justify-between">
<div className="space-y-1">
<div className="flex items-center gap-2">

View file

@ -117,27 +117,6 @@ export default function Home() {
// sessionStorage.setItem('student', studentFilter)
}, [subjectFilter, examinerFilter]);
// Restore scroll position
// TODO: Test and check if needed!!
// // SCROLL
// const setScrollPosition = (colleId: number) => {
// sessionStorage.setItem("colles_position", colleId.toString());
// };
// const restoreScrollPosition = () => {
// const position = sessionStorage.getItem("colles_position");
// if (position) {
// const element = document.getElementById(`colle-${position}`);
// if (element) {
// element.scrollIntoView({ behavior: "smooth", block: "center" });
// sessionStorage.removeItem("colles_position");
// }
// }
// };
// const location = useLocation();
// useEffect(() => {
// setTimeout(restoreScrollPosition, 500);
// }, [location]);
return (
<div className="space-y-6 pb-20 md:pb-0">
{/* Week Navigation */}

View file

@ -84,11 +84,8 @@ export default function TabContent({
<ColleCard
key={colle.id}
colle={colle}
beforeClick={() => {}}
onToggleFavorite={() => {}}
isFavorite={false}
// TODO: Implement scroll position handling
// beforeClick={() => setScrollPosition(colle.id)}
// TODO: Implement favorite toggle
// onToggleFavorite={handleToggleFavorite}
// isFavorite={isFavorite(colle)}

View file

@ -84,14 +84,16 @@ export const useTheme = () => {
return context;
};
const isWindowAvailable = () => {
return typeof window !== "undefined" && window !== null;
}
export const useDisplayedTheme = () => {
const { theme, setTheme } = useTheme();
if (theme === "system") {
return {
theme: window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light",
theme: isWindowAvailable() && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light",
setTheme,
};
}

View file

@ -1,12 +1,8 @@
import { Toaster as Sonner, type ToasterProps } from "sonner";
const Toaster = ({ ...props }: ToasterProps) => {
// TODO: Use theme hook
const { theme = "system" } = {};
return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
style={
{

View file

@ -25,8 +25,6 @@ import { Separator } from "~/components/ui/separator";
import UserDropdown from "~/components/user-dropdown";
import ColleDetailsSkeleton from "~/components/details/skeleton-details";
import AttachmentItem from "~/components/details/attachment";
// TODO: Scroll restoration
// import { ScrollToTopOnMount } from "~/components/noscroll";
import Error from "~/components/error";
import { Badge } from "~/components/ui/badge";
import { AUTH_ERROR, useColle, useUser } from "~/lib/api";
@ -131,8 +129,6 @@ export default function ColleDetailPage() {
return (
<div className="container mx-auto py-6 px-4 pb-20 md:pb-6 md:py-8">
{/* <ScrollToTopOnMount /> */}
<div className="flex justify-between items-center mb-4">
<Button variant="outline" onClick={() => goBack(navigate)}>
<ArrowLeft className="h-4 w-4 mr-2" />

View file

@ -49,14 +49,15 @@
},
"devDependencies": {
"@react-router/dev": "^7.5.3",
"@tailwindcss/vite": "^4.1.4",
"@tailwindcss/vite": "^4.1.11",
"@types/luxon": "^3.7.0",
"@types/node": "^20",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"tailwindcss": "^4.1.4",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^7.0.6",
"vite-plugin-pwa": "^1.0.2",
"vite-tsconfig-paths": "^5.1.4"
}
}

2529
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

35
pwa.config.ts Normal file
View file

@ -0,0 +1,35 @@
export default {
workbox: {
importScripts: ["/sw/push.js"],
},
includeAssets: [
"favicon.ico",
"favicon-96x96.png",
"web-app-manifest-192x192.png",
"web-app-manifest-512x512.png",
"apple-touch-icon.png",
],
registerType: "autoUpdate",
manifest: {
lang: "fr",
name: "Khollisé ⚔️",
short_name: "Khollisé",
description: "BJColle but faster, better and prettier ⚡️",
theme_color: "#0d0d0d",
background_color: "#f4efe3",
orientation: "portrait",
display: "standalone",
icons: [
{
src: "/web-app-manifest-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "/web-app-manifest-512x512.png",
sizes: "512x512",
type: "image/png",
},
],
},
};

View file

@ -1,8 +1,11 @@
import { reactRouter } from "@react-router/dev/vite";
import tailwindcss from "@tailwindcss/vite";
import pwaConfig from "./pwa.config";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({
plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
// @ts-expect-error TODO: Fix type error with VitePWA
plugins: [tailwindcss(), reactRouter(), tsconfigPaths(), VitePWA(pwaConfig)],
});