From 85c12b68ff66c1bbb187b2028fcc03cae8f9b84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20MARQUET?= Date: Thu, 6 Mar 2025 10:19:15 +0100 Subject: [PATCH] Enhance skill display and add tooltip for skill levels --- .gitignore | 23 +++ package-lock.json | 23 +-- package.json | 2 +- src/assets/DATA.ts | 10 +- src/components/SkillCard.tsx | 10 +- src/components/SkillLevel.tsx | 93 ++++++++++ src/i18n.js | 60 ++++++- src/index.js | 17 -- src/output.css | 313 +++++++++++++++++++++------------- 9 files changed, 395 insertions(+), 156 deletions(-) create mode 100644 src/components/SkillLevel.tsx delete mode 100644 src/index.js diff --git a/.gitignore b/.gitignore index 45a5feb..e552789 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,26 @@ yarn-error.log* .idea dist +/src/components/About.js +/src/components/Card.js +/src/components/CV.js +/src/assets/DATA.js +/src/components/Footer.js +/cypress/fixtures/test-redirections/idObjES6Export.js +/cypress/fixtures/test-redirections/idObjES6Import.js +/cypress/fixtures/test-redirections/idObjES6ImportExport.js +/cypress/fixtures/__tests__/import-es6-export-test.js +/cypress/fixtures/__tests__/import-es6-import-export-test.js +/cypress/fixtures/__tests__/import-es6-import-test.js +/cypress/fixtures/__tests__/import-vanilla-test.js +/cypress/fixtures/__tests__/index-test.js +/src/components/Menu.js +/src/components/ProgresBar.js +/src/components/Project.js +/src/components/ProjectCard.js +/cypress/fixtures/__tests__/require-es6-export-test.js +/cypress/fixtures/__tests__/require-es6-import-export-test.js +/cypress/fixtures/__tests__/require-es6-import-test.js +/cypress/fixtures/__tests__/require-vanilla-test.js +/src/components/SkillCard.js +/src/components/Skills.js diff --git a/package-lock.json b/package-lock.json index bb2195e..d378688 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2769,9 +2769,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001677", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz", - "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==", + "version": "1.0.30001702", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001702.tgz", + "integrity": "sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==", "funding": [ { "type": "opencollective", @@ -2785,7 +2785,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/caseless": { "version": "0.12.0", @@ -4763,9 +4764,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true, "funding": [ { @@ -4773,6 +4774,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -6350,10 +6352,11 @@ } }, "node_modules/vite": { - "version": "5.4.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz", - "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", + "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", diff --git a/package.json b/package.json index 4207c40..66e2c15 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "start": "vite", "build": "npx tsc && vite build", "serve": "vite preview", - "build:css": "tailwindcss build src/index.css -o src/output.css", + "build:css": "tailwindcss build -i src/index.css -o src/output.css", "cypress:open": "cypress open", "cypress:run": "cypress run", "test": "browserslist && cypress run" diff --git a/src/assets/DATA.ts b/src/assets/DATA.ts index 5169e4a..cea5592 100644 --- a/src/assets/DATA.ts +++ b/src/assets/DATA.ts @@ -14,11 +14,11 @@ const Felix = { skills: [ { skillName: "C", - skillLevel: 80, + skillLevel: 85, }, { skillName: "C++", - skillLevel: 75, + skillLevel: 80, }, { skillName: "Admin Système", @@ -26,7 +26,7 @@ const Felix = { }, { skillName: "Python", - skillLevel: 75, + skillLevel: 80, }, { skillName: "PHP", @@ -42,7 +42,7 @@ const Felix = { }, { skillName: "Linux", - skillLevel: 75, + skillLevel: 80, }, { skillName: "Go", @@ -58,7 +58,7 @@ const Felix = { }, { skillName: "React", - skillLevel: 70, + skillLevel: 80, } ], projects: [ diff --git a/src/components/SkillCard.tsx b/src/components/SkillCard.tsx index cdd6e55..5684dc4 100644 --- a/src/components/SkillCard.tsx +++ b/src/components/SkillCard.tsx @@ -12,9 +12,9 @@ import { FaRust, FaServer } from 'react-icons/fa'; -//@ts-ignore -import ProgresBar from "./ProgresBar.tsx"; import {FaGolang} from "react-icons/fa6"; +// @ts-ignore +import SkillLevel from "./SkillLevel.tsx"; const iconClassName = "mx-auto text-4xl text-gray-800 dark:text-gray-200"; @@ -45,10 +45,10 @@ type IconMapping = { const SkillCard: React.FC = ({skillName, skillLevel}) => { const skillIcon = iconMapping[skillName]; return( -
+
{skillIcon} -

{skillName}

- +

{skillName}

+
); } diff --git a/src/components/SkillLevel.tsx b/src/components/SkillLevel.tsx new file mode 100644 index 0000000..a0d4eca --- /dev/null +++ b/src/components/SkillLevel.tsx @@ -0,0 +1,93 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; + +interface SkillLevelProps { + level: number; + skillName: string; +} + +const SkillLevel: React.FC = ({ level, skillName }) => { + const [showTooltip, setShowTooltip] = useState(false); + const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 }); + const badgeRef = useRef(null); + const tooltipRef = useRef(null); + const { t } = useTranslation(); + + // Determine skill level text based on numeric value + let skillLevelText; + + if (level < 60) { + skillLevelText = t('skills.beginner'); + } else if (level < 80) { + skillLevelText = t('skills.intermediate'); + } else { + skillLevelText = t('skills.expert'); + } + + const calculatePosition = () => { + if (badgeRef.current && tooltipRef.current) { + const badgeRect = badgeRef.current.getBoundingClientRect(); + const tooltipRect = tooltipRef.current.getBoundingClientRect(); + + // Center tooltip horizontally + const left = badgeRect.left + (badgeRect.width / 2) - (tooltipRect.width / 2); + + // Position tooltip directly below the badge (reduce gap) + const top = badgeRect.bottom + 5; + + // Ensure tooltip stays within viewport + const adjustedLeft = Math.max(10, Math.min(left, window.innerWidth - tooltipRect.width - 10)); + + setTooltipPosition({ top, left: adjustedLeft }); + } + }; + + useEffect(() => { + if (showTooltip) { + calculatePosition(); + // Recalculate position on window resize + window.addEventListener('resize', calculatePosition); + window.addEventListener('scroll', calculatePosition); + + return () => { + window.removeEventListener('resize', calculatePosition); + window.removeEventListener('scroll', calculatePosition); + }; + } + }, [showTooltip]); + + const handleTouch = (e: React.TouchEvent) => { + e.preventDefault(); + setShowTooltip(!showTooltip); + }; + + return ( +
+
setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} + onTouchStart={handleTouch} + > + {skillLevelText} +
+ + {showTooltip && ( +
+

{t(`skills.examples.${skillName}.title`)}

+

{t(`skills.examples.${skillName}.description`)}

+
+ )} +
+ ); +}; + +export default SkillLevel; \ No newline at end of file diff --git a/src/i18n.js b/src/i18n.js index 58b4e09..06c217a 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -8,7 +8,7 @@ i18n fr: { translation: { "about.title": "A propos de moi", - "about.description": "Je suis étudiant en 3e année à l'ISEN Nantes en alternance chez Horoquartz. Je suis passionné par l'informatique. J'ai appris à coder en autodidacte et je suis actuellement en train d'apprendre le C++ et le PHP. Je suis également passionné par l'électronique et le hardware. Je possède un homelab composé de 2 serveur, un DELL T320 et un DELL T330 les 2 sous proxmox.", + "about.description": "Je suis étudiant en 3e année à l'ISEN Nantes en alternance chez Horoquartz. Je suis passionné par l'informatique. J'ai appris à coder en autodidacte et je suis actuellement en train d'apprendre le Rust et le Go. Je suis également passionné par l'électronique et le hardware. Je possède un homelab composé de 3serveur, un DELL T320, un DELL T330 et un Dell Precision T3610 les 3 sous proxmox.", "card.title": "Etudiant en 3e année a l'ISEN Nantes en alternance chez Horoquartz", "projects.title": "Mes projets", "projects.Front end starter.description": "Mon starter personnel pour projet front end", @@ -23,13 +23,40 @@ i18n "nav.about": "A propos de moi", "nav.projects": "Mes projets", "nav.cv": "Mon CV", + "skills.beginner": "Débutant", + "skills.intermediate": "Intermédiaire", + "skills.expert": "Expert", + "skills.examples.C.title": "Projets C", + "skills.examples.C.description": "Projet de fin de 1ère année à l'ISEN, algorithmes de base, création d'une api REST", + "skills.examples.C++.title": "Projets C++", + "skills.examples.C++.description": "Tower Defense en Qt6, simulation de banc de poissons avec SDL2 avec support du multijoueur, algorithmes de base", + "skills.examples.Admin Système.title": "Administration Système", + "skills.examples.Admin Système.description": "Configuration de 3 serveurs DELL sous Proxmox, virtualisation, maintenance des machines virtuelles", + "skills.examples.Python.title": "Projets Python", + "skills.examples.Python.description": "Github NTFY pour les notifications des releases github et dockerhub, projets de cours", + "skills.examples.PHP.title": "Projets PHP", + "skills.examples.PHP.description": "Développements web avec PHP, AJAX, postgreSQL", + "skills.examples.HTML/CSS.title": "Développement Front-end", + "skills.examples.HTML/CSS.description": "Front-end starter personnalisé, projet de base, divers projets web", + "skills.examples.JS/TS.title": "JavaScript/TypeScript", + "skills.examples.JS/TS.description": "Développement React, ce portfolio, api NodeJS avec Express, Création d'une application mobile ISEN Orbit avec React Native, projets professionnels", + "skills.examples.Linux.title": "Administration Linux", + "skills.examples.Linux.description": "Configuration de serveurs, administration système, Ansible playbooks", + "skills.examples.Go.title": "Projets Go", + "skills.examples.Go.description": "Initiation au langage, Création d'une api REST avec Fiber, Go Gin et la librairie standard, projets professionnels", + "skills.examples.Docker.title": "Containerisation", + "skills.examples.Docker.description": "Déploiement de conteneurs, configuration Docker Compose, création d'images, déploiement de services en haute disponibilité via Swarm et Kubernetes", + "skills.examples.Rust.title": "Projets Rust", + "skills.examples.Rust.description": "Apprentissage du langage, création d'une api REST avec Ntex", + "skills.examples.React.title": "Développement React", + "skills.examples.React.description": "Ce portfolio, site web de Modelec, application mobile ISEN Orbit, projets professionnels", }, }, en: { translation: { "cv.title": "My CV", "about.title": "About me", - "about.description": "I am a thrid year student at ISEN Nantes in work-study program at Horoquartz. I am passionate about computer science. I learned to code on my own and I am currently learning C++ and PHP. I am also passionate about electronics and hardware. I have a homelab composed of 2 servers, a DELL T320 and a DELL T330 both under proxmox.", + "about.description": "I am a third-year student at ISEN Nantes, currently in a work-study program at Horoquartz. I am passionate about computer science. I learned to code on my own and am currently learning Rust and Go. I am also passionate about electronics and hardware. I have a homelab consisting of 3 servers: a DELL T320, a DELL T330, and a Dell Precision T3610, all running Proxmox.", "card.title": "Third year student at ISEN Nantes in work-study program at Horoquartz", "projects.title": "My projects", "projects.Front end starter.description": "My personal starter for front end projects", @@ -42,7 +69,34 @@ i18n "nav.about": "About me", "nav.projects": "My projects", "nav.cv": "My CV", - "cv.path": "/CV%20Félix%20MARQUET%20ENGLISH.pdf" + "cv.path": "/CV%20Félix%20MARQUET%20ENGLISH.pdf", + "skills.beginner": "Beginner", + "skills.intermediate": "Intermediate", + "skills.expert": "Expert", + "skills.examples.C.title": "C Projects", + "skills.examples.C.description": "End-of-first-year project at ISEN, basic algorithms, creation of a REST API.", + "skills.examples.C++.title": "C++ Projects", + "skills.examples.C++.description": "Tower Defense in Qt6, fish school simulation with SDL2 featuring multiplayer support, basic algorithms.", + "skills.examples.Admin Système.title": "System Administration", + "skills.examples.Admin Système.description": "Configuration of 3 DELL servers under Proxmox, virtualization, maintenance of virtual machines.", + "skills.examples.Python.title": "Python Projects", + "skills.examples.Python.description": "GitHub NTFY for GitHub and DockerHub release notifications, course projects.", + "skills.examples.PHP.title": "PHP Projects", + "skills.examples.PHP.description": "Web development with PHP, AJAX, PostgreSQL.", + "skills.examples.HTML/CSS.title": "Front-end development", + "skills.examples.HTML/CSS.description": "Custom front-end starter, base project, various web projects.", + "skills.examples.JS/TS.title": "JavaScript/TypeScript", + "skills.examples.JS/TS.description": "React development, this portfolio, NodeJS API with Express, creation of the ISEN Orbit mobile application with React Native, professional projects.", + "skills.examples.Linux.title": "Linux Administration", + "skills.examples.Linux.description": "Server configuration, system administration, Ansible playbooks.", + "skills.examples.Go.title": "Go Projects", + "skills.examples.Go.description": "Introduction to the language, creation of a REST API with Fiber, Go Gin, and the standard library, professional projects.", + "skills.examples.Docker.title": "Containerization", + "skills.examples.Docker.description": "Container deployment, Docker Compose configuration, image creation, high-availability service deployment via Swarm and Kubernetes.", + "skills.examples.Rust.title": "Rust Projects", + "skills.examples.Rust.description": "Learning the language, creation of a REST API with Ntex.", + "skills.examples.React.title": "React Development", + "skills.examples.React.description": "This portfolio, Modelec website, ISEN Orbit mobile application, professional projects." }, }, }, diff --git a/src/index.js b/src/index.js deleted file mode 100644 index d563c0f..0000000 --- a/src/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; - -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - - -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); diff --git a/src/output.css b/src/output.css index 11216da..10f2e4c 100644 --- a/src/output.css +++ b/src/output.css @@ -1,5 +1,113 @@ +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + /* -! tailwindcss v3.4.4 | MIT License | https://tailwindcss.com +! tailwindcss v3.4.14 | MIT License | https://tailwindcss.com */ /* @@ -433,116 +541,42 @@ video { /* Make elements with the HTML hidden attribute stay hidden by default */ -[hidden] { +[hidden]:where(:not([hidden="until-found"])) { display: none; } -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; +.container { + width: 100%; } -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; - --tw-contain-size: ; - --tw-contain-layout: ; - --tw-contain-paint: ; - --tw-contain-style: ; +@media (min-width: 640px) { + .container { + max-width: 640px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 768px; + } +} + +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } +} + +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } } .sr-only { @@ -581,6 +615,10 @@ video { z-index: 50; } +.m-0 { + margin: 0px; +} + .m-1 { margin: 0.25rem; } @@ -599,6 +637,10 @@ video { margin-bottom: 1rem; } +.mb-1 { + margin-bottom: 0.25rem; +} + .mb-4 { margin-bottom: 1rem; } @@ -611,6 +653,10 @@ video { margin-top: 4rem; } +.mt-2 { + margin-top: 0.5rem; +} + .mt-3 { margin-top: 0.75rem; } @@ -655,6 +701,10 @@ video { width: 10rem; } +.w-64 { + width: 16rem; +} + .w-auto { width: auto; } @@ -675,6 +725,14 @@ video { flex: none; } +.cursor-pointer { + cursor: pointer; +} + +.resize { + resize: both; +} + .flex-row { flex-direction: row; } @@ -723,6 +781,10 @@ video { border-radius: 0.75rem; } +.border { + border-width: 1px; +} + .border-2 { border-width: 2px; } @@ -745,6 +807,11 @@ video { background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + .bg-white { --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); @@ -758,6 +825,10 @@ video { padding: 0.5rem; } +.p-3 { + padding: 0.75rem; +} + .p-4 { padding: 1rem; } @@ -830,6 +901,11 @@ video { line-height: 1.5rem; } +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + .text-xl { font-size: 1.25rem; line-height: 1.75rem; @@ -848,6 +924,10 @@ video { font-weight: 800; } +.font-medium { + font-weight: 500; +} + .font-semibold { font-weight: 600; } @@ -912,6 +992,12 @@ video { transition-duration: 150ms; } +.transition-shadow { + transition-property: box-shadow; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + .duration-300 { transition-duration: 300ms; } @@ -930,6 +1016,12 @@ video { color: rgb(255 255 255 / var(--tw-text-opacity)); } +.hover\:shadow-lg:hover { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + .dark\:border-gray-700:is(.dark *) { --tw-border-opacity: 1; border-color: rgb(55 65 81 / var(--tw-border-opacity)); @@ -993,19 +1085,10 @@ video { width: 41.666667%; } - .sm\:flex-row { - flex-direction: row; - } - .sm\:p-2 { padding: 0.5rem; } - .sm\:px-5 { - padding-left: 1.25rem; - padding-right: 1.25rem; - } - .sm\:text-2xl { font-size: 1.5rem; line-height: 2rem;