tuned header of recipe lists for smartphones
This commit is contained in:
parent
5c3c74b32e
commit
686eddbaee
24 changed files with 2563 additions and 29 deletions
3
frontend/.gitignore
vendored
3
frontend/.gitignore
vendored
|
|
@ -12,6 +12,9 @@ dist
|
|||
dist-ssr
|
||||
*.local
|
||||
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
|
|
|
|||
18
frontend/package-lock.json
generated
18
frontend/package-lock.json
generated
|
|
@ -15,6 +15,7 @@
|
|||
"devDependencies": {
|
||||
"@eslint/js": "^9.33.0",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@types/node": "^24.4.0",
|
||||
"@types/react": "^19.1.10",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
|
|
@ -1718,6 +1719,16 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.4.0.tgz",
|
||||
"integrity": "sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz",
|
||||
|
|
@ -4030,6 +4041,13 @@
|
|||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.11.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.11.0.tgz",
|
||||
"integrity": "sha512-kt1ZriHTi7MU+Z/r9DOdAI3ONdaR3M3csEaRc6ewa4f4dTvX4cQCbJ4NkEn0ohE4hHtq85+PhPSTY+pO/1PwgA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
"devDependencies": {
|
||||
"@eslint/js": "^9.33.0",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"@types/node": "^24.4.0",
|
||||
"@types/react": "^19.1.10",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
import type { Recipe } from "../types/recipe"
|
||||
import { API_BASE_URL } from "../config/api"
|
||||
|
||||
|
||||
/**
|
||||
* Util for handling the recipe api
|
||||
*/
|
||||
// reate base url from .env file
|
||||
const BASE_URL = import.meta.env.VITE_API_BASE;
|
||||
|
||||
/**
|
||||
* URL for handling recipes
|
||||
*/
|
||||
const RECIPE_URL = `${API_BASE_URL}/recipe`
|
||||
const RECIPE_URL = `${BASE_URL}/recipe`
|
||||
|
||||
/**
|
||||
* Load a single recipe
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export default function RecipeListPage() {
|
|||
navigate(getRecipeAddUrl())
|
||||
}
|
||||
|
||||
if(!recipeList) { return <div>Unable to load recipes!</div>}
|
||||
if(!recipeList) { return <div>Loading!</div>}
|
||||
return (
|
||||
/*Container spanning entire screen used to center content horizontally */
|
||||
<div className="w-screen min-h-screen flex justify-center">
|
||||
|
|
@ -44,20 +44,24 @@ export default function RecipeListPage() {
|
|||
{/* Header - remains in position when scrolling */}
|
||||
<div className="sticky bg-gray-100 top-0 left-0 right-0 pb-4 border-b-2 border-gray-300">
|
||||
<h1 className="content-title text-blue-900">Recipes</h1>
|
||||
<div className="flex columns-4 content-stretch gap-2 items-center">
|
||||
{/* Number of recipes inlist */}
|
||||
<label className="label w-2/3">{recipeList.length} Recipes</label>
|
||||
{/* Search field */}
|
||||
<SearchField
|
||||
searchString=""
|
||||
onSearchStringChanged={setSearchString}
|
||||
/>
|
||||
{/* Add recipe button */}
|
||||
<button className="primary-button"
|
||||
onClick={handleAdd}
|
||||
>
|
||||
Add recipe
|
||||
</button>
|
||||
<div className="flex flex-wrap items-center gap-2 w-full">
|
||||
{/* Label: left-aligned on medium+ screens, full-width on small screens */}
|
||||
<div className="order-2 md:order-1 w-full md:w-auto md:flex-1">
|
||||
<label className="label">{recipeList.length} Recipes</label>
|
||||
</div>
|
||||
|
||||
{/* Search + Add button container: right-aligned on medium+ screens */}
|
||||
<div className="order-1 md:order-2 flex flex-1 md:flex-none justify-end gap-2 min-w-[160px]">
|
||||
<div className="flex-1 md:flex-none md:max-w-[500px]">
|
||||
<SearchField onSearchStringChanged={setSearchString} />
|
||||
</div>
|
||||
<button
|
||||
className="primary-button flex-shrink-0"
|
||||
onClick={handleAdd}
|
||||
>
|
||||
Add recipe
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/*Content - List of recipe cards */}
|
||||
|
|
@ -74,3 +78,38 @@ export default function RecipeListPage() {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// /*Container spanning entire screen used to center content horizontally */
|
||||
// <div className="w-screen min-h-screen flex justify-center">
|
||||
// {/* Container defining the maximum width of the content */}
|
||||
// <div className="bg-gray-100 w-full min-h-screen max-w-5xl shadow-xl p-8">
|
||||
// {/* Header - remains in position when scrolling */}
|
||||
// <div className="sticky bg-gray-100 top-0 left-0 right-0 pb-4 border-b-2 border-gray-300">
|
||||
// <h1 className="content-title text-blue-900">Recipes</h1>
|
||||
// <div className="flex columns-4 content-stretch gap-2 items-center">
|
||||
// {/* Number of recipes inlist */}
|
||||
// <label className="label w-2/3">{recipeList.length} Recipes</label>
|
||||
// {/* Search field */}
|
||||
// <SearchField
|
||||
// onSearchStringChanged={setSearchString}
|
||||
// />
|
||||
// {/* Add recipe button */}
|
||||
// <button className="primary-button"
|
||||
// onClick={handleAdd}
|
||||
// >
|
||||
// Add recipe
|
||||
// </button>
|
||||
// </div>
|
||||
// </div>
|
||||
// {/*Content - List of recipe cards */}
|
||||
// <div className="grid pt-4 gap-6 grid-cols-[repeat(auto-fit,minmax(220px,1fr))]">
|
||||
// {recipeList.map((recipe) => (
|
||||
// <RecipeListItem
|
||||
// key={recipe.id}
|
||||
// title = {recipe.title}
|
||||
// targetPath={getRecipeDetailUrl(recipe.id)}
|
||||
// />
|
||||
// ))}
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/**
|
||||
* Backend URL
|
||||
*/
|
||||
export const API_BASE_URL = "http://localhost:4000"
|
||||
//export const API_BASE_URL = "http://localhost:4000"
|
||||
export const API_BASE_URL = "http://10.0.1.152:4000"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
import { defineConfig } from "vite"
|
||||
import { defineConfig, loadEnv } from "vite"
|
||||
import react from "@vitejs/plugin-react"
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), "")
|
||||
return {
|
||||
plugins: [react()],
|
||||
server: {
|
||||
host: env.VITE_HOST || "localhost",
|
||||
port: Number(env.VITE_PORT) || 5173,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue