SebastianSchramm commited on
Commit
6e75715
·
unverified ·
1 Parent(s): c1b0c90

pimp the app

Browse files
index.html CHANGED
@@ -2,7 +2,7 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8" />
5
- <link rel="icon" type="image/png" href="/assets/logo.png" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
  <title>Vite + React</title>
8
  </head>
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="src/assets/logo.png" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
  <title>Vite + React</title>
8
  </head>
package-lock.json CHANGED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -1,30 +1,27 @@
1
  {
2
  "name": "emotions",
 
3
  "private": true,
4
- "version": "0.0.0",
5
- "type": "module",
6
  "scripts": {
7
  "dev": "vite",
8
- "build": "vite build",
9
- "lint": "eslint .",
10
  "preview": "vite preview"
11
  },
12
  "dependencies": {
13
- "react": "^19.1.0",
14
- "react-dom": "^19.1.0"
 
15
  },
16
  "devDependencies": {
17
- "@eslint/js": "^9.30.1",
18
- "@types/react": "^19.1.8",
19
- "@types/react-dom": "^19.1.6",
20
- "@vitejs/plugin-react": "^4.6.0",
21
- "autoprefixer": "^10.4.21",
22
- "eslint": "^9.30.1",
23
- "eslint-plugin-react-hooks": "^5.2.0",
24
- "eslint-plugin-react-refresh": "^0.4.20",
25
- "globals": "^16.3.0",
26
- "postcss": "^8.5.6",
27
- "tailwindcss": "^4.1.11",
28
- "vite": "^5.4.0"
29
  }
30
  }
 
1
  {
2
  "name": "emotions",
3
+ "version": "1.0.0",
4
  "private": true,
 
 
5
  "scripts": {
6
  "dev": "vite",
7
+ "build": "vite build && cp public/_headers dist/",
 
8
  "preview": "vite preview"
9
  },
10
  "dependencies": {
11
+ "lucide-react": "^0.534.0",
12
+ "react": "^18.2.0",
13
+ "react-dom": "^18.2.0"
14
  },
15
  "devDependencies": {
16
+ "@testing-library/jest-dom": "^6.6.3",
17
+ "@testing-library/react": "^16.3.0",
18
+ "@vitejs/plugin-react": "^4.0.0",
19
+ "autoprefixer": "^10.4.15",
20
+ "jsdom": "^26.1.0",
21
+ "postcss": "^8.4.24",
22
+ "tailwindcss": "^3.3.2",
23
+ "vite": "^5.0.0",
24
+ "vite-plugin-pwa": "^0.16.4",
25
+ "vitest": "^3.2.4"
 
 
26
  }
27
  }
postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
public/favicon.ico DELETED
Binary file (3.87 kB)
 
public/index.html DELETED
@@ -1,43 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <meta name="theme-color" content="#000000" />
8
- <meta
9
- name="description"
10
- content="Web site created using create-react-app"
11
- />
12
- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13
- <!--
14
- manifest.json provides metadata used when your web app is installed on a
15
- user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16
- -->
17
- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
18
- <!--
19
- Notice the use of %PUBLIC_URL% in the tags above.
20
- It will be replaced with the URL of the `public` folder during the build.
21
- Only files inside the `public` folder can be referenced from the HTML.
22
-
23
- Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
24
- work correctly both with client-side routing and a non-root public URL.
25
- Learn how to configure a non-root public URL by running `npm run build`.
26
- -->
27
- <title>React App</title>
28
- </head>
29
- <body>
30
- <noscript>You need to enable JavaScript to run this app.</noscript>
31
- <div id="root"></div>
32
- <!--
33
- This HTML file is a template.
34
- If you open it directly in the browser, you will see an empty page.
35
-
36
- You can add webfonts, meta tags, or analytics to this file.
37
- The build step will place the bundled scripts into the <body> tag.
38
-
39
- To begin the development, run `npm start` or `yarn start`.
40
- To create a production bundle, use `npm run build` or `yarn build`.
41
- -->
42
- </body>
43
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/manifest.json DELETED
@@ -1,25 +0,0 @@
1
- {
2
- "short_name": "React App",
3
- "name": "Create React App Sample",
4
- "icons": [
5
- {
6
- "src": "favicon.ico",
7
- "sizes": "64x64 32x32 24x24 16x16",
8
- "type": "image/x-icon"
9
- },
10
- {
11
- "src": "logo192.png",
12
- "type": "image/png",
13
- "sizes": "192x192"
14
- },
15
- {
16
- "src": "logo512.png",
17
- "type": "image/png",
18
- "sizes": "512x512"
19
- }
20
- ],
21
- "start_url": ".",
22
- "display": "standalone",
23
- "theme_color": "#000000",
24
- "background_color": "#ffffff"
25
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/vite.svg DELETED
src/App.jsx CHANGED
@@ -57,34 +57,67 @@ function App() {
57
  };
58
 
59
  return (
60
- <div className="min-h-screen bg-pink-100 pt-28 pb-10 px-4 text-center relative">
61
- {/* Fixed Top Banner */}
62
- <div className="fixed top-0 left-0 w-full bg-pink-200 shadow-md z-10 py-3 flex justify-center items-center">
63
- <img src={logo} alt="Logo" className="h-12 object-contain" />
64
- </div>
 
 
 
65
 
66
- {/* Flag Dropdown */}
67
- <div className="mb-4">
68
- <FlagDropdown country={country} setCountry={setCountry} />
69
- </div>
70
 
71
- {/* Story Button Card */}
72
- <div className="bg-white rounded-2xl shadow-lg p-6 mb-6 max-w-md mx-auto w-full">
73
- <h1 className="text-2xl font-bold text-purple-600 mb-4">Story Time</h1>
74
- <StoryButton onClick={handleReadStory} disabled={loading} />
75
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
- {/* Emotions Card */}
78
- <div className="bg-white rounded-2xl shadow-lg p-6 max-w-md mx-auto w-full">
79
- <h2 className="text-lg font-semibold text-purple-600 mb-4">Feeling something?</h2>
80
- <div className="flex justify-center gap-4 flex-wrap">
81
- <EmotionButton emotion="Anxiety" onClick={() => handleEmotion("Anxiety")} />
82
- <EmotionButton emotion="Sadness" onClick={() => handleEmotion("Sadness")} />
83
- <EmotionButton emotion="Anger" onClick={() => handleEmotion("Anger")} />
84
  </div>
85
  </div>
86
  </div>
87
  );
88
  }
89
 
90
- export default App;
 
57
  };
58
 
59
  return (
60
+ <div className="bg-purple-100 flex flex-col">
61
+ {/* Fixed Top Banner */}
62
+ <div className="fixed top-0 left-0 w-full bg-purple-200 shadow-md z-10 py-3 flex items-center justify-center relative">
63
+
64
+ {/* Flag Dropdown on the left with max-width 500px */}
65
+ <div className="absolute left-4 sm:left-8 md:left-100 max-w-[100px]">
66
+ <FlagDropdown country={country} setCountry={setCountry} />
67
+ </div>
68
 
69
+ {/* Logo centered */}
70
+ <img src={logo} alt="Logo" className="h-16 object-contain rounded-2xl mx-auto" />
 
 
71
 
72
+ </div>
73
+
74
+
75
+ {/* Main Content - Centered */}
76
+ <div className="flex-1 flex py-80 justify-center items-center pt-20">
77
+ <div className="max-w-sm mx-auto w-full flex flex-col items-center gap-12 px-4">
78
+
79
+
80
+ {/* Story Button Card */}
81
+ <div className="bg-[#fad465]/70 rounded-2xl shadow-lg p-6 w-full">
82
+ <div className="flex justify-center">
83
+
84
+ <StoryButton onClick={handleReadStory} disabled={loading} />
85
+
86
+ </div>
87
+ </div>
88
+
89
+ {/* Emotions Cards - One button per card */}
90
+ <div className="w-full flex flex-col gap-4">
91
+
92
+ <div className="bg-[#d6e483]/70 rounded-2xl shadow-lg p-6 w-full">
93
+ <div className="flex justify-center">
94
+
95
+ <EmotionButton emotion="Anxiety" onClick={() => handleEmotion("Anxiety")} />
96
+
97
+ </div>
98
+ </div>
99
+
100
+ <div className="bg-[#7892dd]/70 rounded-2xl shadow-lg p-6 w-full">
101
+ <div className="flex justify-center">
102
+
103
+ <EmotionButton emotion="Sadness" onClick={() => handleEmotion("Sadness")} />
104
+
105
+ </div>
106
+ </div>
107
+
108
+ <div className="bg-[#f94a3f]/70 rounded-2xl shadow-lg p-6 w-full">
109
+ <div className="flex justify-center">
110
+
111
+ <EmotionButton emotion="Anger" onClick={() => handleEmotion("Anger")} />
112
+
113
+ </div>
114
+ </div>
115
+ </div>
116
 
 
 
 
 
 
 
 
117
  </div>
118
  </div>
119
  </div>
120
  );
121
  }
122
 
123
+ export default App;
src/assets/anger.png CHANGED

Git LFS Details

  • SHA256: 9c3f8e6b3ec564564aff51f0640c87bfca0e90a044ac3c51e11f27cfac5b5f9c
  • Pointer size: 130 Bytes
  • Size of remote file: 55.4 kB

Git LFS Details

  • SHA256: c23b32d9cef4f4500a89bf243c06237cdf4c0ff2d6e7a5706eb2a04c6114f6c9
  • Pointer size: 132 Bytes
  • Size of remote file: 1.37 MB
public/logo192.png → src/assets/anger_original.png RENAMED
File without changes
src/assets/anxiety.png CHANGED

Git LFS Details

  • SHA256: 9c3f8e6b3ec564564aff51f0640c87bfca0e90a044ac3c51e11f27cfac5b5f9c
  • Pointer size: 130 Bytes
  • Size of remote file: 55.4 kB

Git LFS Details

  • SHA256: 6918329f5a9c6769820a549f64307cdf2799681412ecf4f94afb44a28fb4bc10
  • Pointer size: 132 Bytes
  • Size of remote file: 3.53 MB
src/assets/logo.png CHANGED

Git LFS Details

  • SHA256: 5789b15648389c7deacec02d2475a5f1308f66e5f01ae76f0b67d28992854d59
  • Pointer size: 131 Bytes
  • Size of remote file: 809 kB

Git LFS Details

  • SHA256: 87555c5f66d732459ce262d532b1b29444b54f8eef94d873238a37b2db79b24f
  • Pointer size: 132 Bytes
  • Size of remote file: 2.05 MB
public/logo512.png → src/assets/logo_v12.png RENAMED
File without changes
src/assets/react.svg DELETED
src/assets/sadness.png CHANGED

Git LFS Details

  • SHA256: 9c3f8e6b3ec564564aff51f0640c87bfca0e90a044ac3c51e11f27cfac5b5f9c
  • Pointer size: 130 Bytes
  • Size of remote file: 55.4 kB

Git LFS Details

  • SHA256: 7e8ffd7cc771a217d96b0ddcc21b71c5bc47c7817d8c0997d2504e55c99719ed
  • Pointer size: 132 Bytes
  • Size of remote file: 3.41 MB
src/assets/story.png CHANGED

Git LFS Details

  • SHA256: 9c3f8e6b3ec564564aff51f0640c87bfca0e90a044ac3c51e11f27cfac5b5f9c
  • Pointer size: 130 Bytes
  • Size of remote file: 55.4 kB

Git LFS Details

  • SHA256: c8a60309cb3e489b9b3cc799237fed44d4248d82ae929ded8993fc2518bf4657
  • Pointer size: 132 Bytes
  • Size of remote file: 3.43 MB
src/components/EmotionButton.jsx CHANGED
@@ -12,7 +12,7 @@ const EmotionButton = ({ emotion, onClick }) => {
12
  const img = emotionImages[emotion];
13
 
14
  return (
15
- <button onClick={onClick} className="w-24 h-24 rounded-full overflow-hidden shadow-md hover:scale-105 transition">
16
  <img src={img} alt={emotion} className="w-full h-full object-cover" />
17
  </button>
18
  );
 
12
  const img = emotionImages[emotion];
13
 
14
  return (
15
+ <button onClick={onClick} className="w-40 h-40 rounded-[2.5rem] overflow-hidden shadow-md hover:scale-105 transition">
16
  <img src={img} alt={emotion} className="w-full h-full object-cover" />
17
  </button>
18
  );
src/components/FlagDropdown.jsx CHANGED
@@ -1,8 +1,9 @@
1
  import { useState } from "react";
 
2
  import usaFlag from "../assets/usa.png";
3
  import costaRicaFlag from "../assets/costa_rica.png";
4
 
5
- // Include the language code for each country
6
  const countries = [
7
  { name: "USA", flag: usaFlag, language: "en" },
8
  { name: "Costa Rica", flag: costaRicaFlag, language: "es" },
@@ -10,32 +11,38 @@ const countries = [
10
 
11
  const FlagDropdown = ({ country, setCountry }) => {
12
  const [isOpen, setIsOpen] = useState(false);
13
-
14
- // Match by country name
15
  const selected = countries.find((c) => c.name === country.name) || countries[0];
16
 
17
  const toggleDropdown = () => setIsOpen(!isOpen);
18
 
19
  const selectCountry = (countryObj) => {
20
- setCountry(countryObj); // Pass full object including language
21
  setIsOpen(false);
22
  };
23
 
24
  return (
25
- <div className="relative inline-block">
26
- <button onClick={toggleDropdown} className="p-1 border rounded">
27
- <img src={selected.flag} className="w-10 h-6 sm:w-12 sm:h-8 rounded shadow" />
 
 
 
 
 
 
 
 
28
  </button>
29
 
30
  {isOpen && (
31
- <div className="absolute mt-2 bg-white border rounded shadow-md z-10">
32
  {countries.map((c) => (
33
  <div
34
  key={c.name}
35
  onClick={() => selectCountry(c)}
36
- className="cursor-pointer hover:bg-gray-100 p-1"
37
  >
38
- <img src={c.flag} alt={c.name} className="w-10 h-6" />
39
  </div>
40
  ))}
41
  </div>
 
1
  import { useState } from "react";
2
+ import { ChevronDown } from "lucide-react"; // Optional for dropdown icon
3
  import usaFlag from "../assets/usa.png";
4
  import costaRicaFlag from "../assets/costa_rica.png";
5
 
6
+ // Country data
7
  const countries = [
8
  { name: "USA", flag: usaFlag, language: "en" },
9
  { name: "Costa Rica", flag: costaRicaFlag, language: "es" },
 
11
 
12
  const FlagDropdown = ({ country, setCountry }) => {
13
  const [isOpen, setIsOpen] = useState(false);
 
 
14
  const selected = countries.find((c) => c.name === country.name) || countries[0];
15
 
16
  const toggleDropdown = () => setIsOpen(!isOpen);
17
 
18
  const selectCountry = (countryObj) => {
19
+ setCountry(countryObj);
20
  setIsOpen(false);
21
  };
22
 
23
  return (
24
+ <div className="relative inline-block w-16 ">
25
+ <button
26
+ onClick={toggleDropdown}
27
+ className="flex items-center justify-center w-full p-1.5 border border-gray-300 rounded-lg shadow-sm bg-white hover:border-gray-400"
28
+ >
29
+ <img
30
+ src={selected.flag}
31
+ className="w-8 h-4 sm:h-6 rounded min-h-[30px]"
32
+ alt={selected.name}
33
+ />
34
+ <ChevronDown className="w-4 h-4 ml-1 text-gray-600" />
35
  </button>
36
 
37
  {isOpen && (
38
+ <div className="absolute mt-1 w-full bg-white border border-gray-300 rounded-lg shadow-md z-10">
39
  {countries.map((c) => (
40
  <div
41
  key={c.name}
42
  onClick={() => selectCountry(c)}
43
+ className="flex justify-center p-2 cursor-pointer hover:bg-gray-100"
44
  >
45
+ <img src={c.flag} alt={c.name} className="h-4 w-6 sm:h-5 sm:w-8 rounded-sm" />
46
  </div>
47
  ))}
48
  </div>
src/components/StoryButton.jsx CHANGED
@@ -3,7 +3,7 @@ import readStoryImg from "../assets/story.png";
3
  const StoryButton = ({ onClick }) => (
4
  <button
5
  onClick={onClick}
6
- className="w-40 h-40 sm:w-48 sm:h-48 rounded-full overflow-hidden shadow-lg hover:scale-105 transition"
7
  >
8
  <img src={readStoryImg} alt="Read a story" className="w-full h-full object-contain" />
9
  </button>
 
3
  const StoryButton = ({ onClick }) => (
4
  <button
5
  onClick={onClick}
6
+ className="w-40 h-40 sm:w-48 sm:h-48 rounded-[3rem] overflow-hidden shadow-lg hover:scale-105 transition"
7
  >
8
  <img src={readStoryImg} alt="Read a story" className="w-full h-full object-contain" />
9
  </button>
vite.config.js CHANGED
@@ -1,7 +1,33 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
 
3
 
4
- // https://vite.dev/config/
5
  export default defineConfig({
6
- plugins: [react()],
7
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import { VitePWA } from 'vite-plugin-pwa';
4
 
 
5
  export default defineConfig({
6
+ plugins: [
7
+ react(),
8
+ VitePWA({
9
+ registerType: 'autoUpdate',
10
+ includeAssets: ['favicon.ico', 'icon-192.png', 'icon-512.png'],
11
+ manifest: {
12
+ name: "Emotions",
13
+ short_name: "Emotions",
14
+ theme_color: "#1A4FA3",
15
+ background_color: "#ffffff",
16
+ display: "standalone",
17
+ start_url: ".",
18
+ icons: [
19
+ {
20
+ src: "icon-192.png",
21
+ sizes: "192x192",
22
+ type: "image/png"
23
+ },
24
+ {
25
+ src: "icon-512.png",
26
+ sizes: "512x512",
27
+ type: "image/png"
28
+ }
29
+ ]
30
+ }
31
+ })
32
+ ]
33
+ });