Compare commits

...

2 Commits

Author SHA1 Message Date
32d387c94b Redesign meal time cards in planner
All checks were successful
Build and Deploy / build-and-push (push) Successful in 1m23s
2026-04-07 19:45:18 +02:00
62d3ee1ddd Redesign meal time cards in planner 2026-04-07 14:34:26 +02:00
4 changed files with 64 additions and 80 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
.DS_Store .DS_Store
.idea/workspace.xml

77
.idea/workspace.xml generated
View File

@@ -5,12 +5,9 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="ae0e4ce8-372f-4cfd-a04f-600640f32223" name="Changes" comment="Restore gitea action"> <list default="true" id="ae0e4ce8-372f-4cfd-a04f-600640f32223" name="Changes" comment="Restore gitea action">
<change beforePath="$PROJECT_DIR$/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/index.html" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change beforePath="$PROJECT_DIR$/js/app.js" beforeDir="false" afterPath="$PROJECT_DIR$/js/app.js" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/js/data/catalog.js" beforeDir="false" afterPath="$PROJECT_DIR$/js/data/catalog.js" afterDir="false" /> <change beforePath="$PROJECT_DIR$/js/views/MealPlanner.js" beforeDir="false" afterPath="$PROJECT_DIR$/js/views/MealPlanner.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/js/views/Filter.js" beforeDir="false" afterPath="$PROJECT_DIR$/js/views/Filter.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/js/views/RecipeList.js" beforeDir="false" afterPath="$PROJECT_DIR$/js/views/RecipeList.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/manifest.webmanifest" beforeDir="false" afterPath="$PROJECT_DIR$/manifest.webmanifest" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -30,50 +27,50 @@
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
<component name="KubernetesApiPersistence"><![CDATA[{}]]></component> <component name="KubernetesApiPersistence">{}</component>
<component name="KubernetesApiProvider"><![CDATA[{ <component name="KubernetesApiProvider">{
"isMigrated": true &quot;isMigrated&quot;: true
}]]></component> }</component>
<component name="McpProjectServerCommands"> <component name="McpProjectServerCommands">
<commands /> <commands />
<urls /> <urls />
</component> </component>
<component name="ProjectColorInfo"><![CDATA[{ <component name="ProjectColorInfo">{
"associatedIndex": 8, &quot;associatedIndex&quot;: 8,
"fromUser": false &quot;fromUser&quot;: false
}]]></component> }</component>
<component name="ProjectId" id="3BqiA2Jye2iyFuy4jKirNGx94l7" /> <component name="ProjectId" id="3BqiA2Jye2iyFuy4jKirNGx94l7" />
<component name="ProjectViewState"> <component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent"><![CDATA[{ <component name="PropertiesComponent">{
"keyToString": { &quot;keyToString&quot;: {
"ModuleVcsDetector.initialDetectionPerformed": "true", &quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;,
"RunOnceActivity.MCP Project settings loaded": "true", &quot;RunOnceActivity.MCP Project settings loaded&quot;: &quot;true&quot;,
"RunOnceActivity.ShowReadmeOnStart": "true", &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true", &quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;,
"RunOnceActivity.cidr.known.project.marker": "true", &quot;RunOnceActivity.cidr.known.project.marker&quot;: &quot;true&quot;,
"RunOnceActivity.git.unshallow": "true", &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
"RunOnceActivity.readMode.enableVisualFormatting": "true", &quot;RunOnceActivity.readMode.enableVisualFormatting&quot;: &quot;true&quot;,
"RunOnceActivity.typescript.service.memoryLimit.init": "true", &quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;,
"cidr.known.project.marker": "true", &quot;cidr.known.project.marker&quot;: &quot;true&quot;,
"codeWithMe.voiceChat.enabledByDefault": "false", &quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;,
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true", &quot;com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1&quot;: &quot;true&quot;,
"git-widget-placeholder": "master", &quot;git-widget-placeholder&quot;: &quot;master&quot;,
"junie.onboarding.icon.badge.shown": "true", &quot;junie.onboarding.icon.badge.shown&quot;: &quot;true&quot;,
"kotlin-language-version-configured": "true", &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
"last_opened_file_path": "/Users/rwilk/dev/repo/recipe-mockup", &quot;last_opened_file_path&quot;: &quot;/Users/rwilk/dev/repo/recipe-mockup&quot;,
"node.js.detected.package.eslint": "true", &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
"node.js.detected.package.tslint": "true", &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
"node.js.selected.package.eslint": "(autodetect)", &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
"node.js.selected.package.tslint": "(autodetect)", &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
"nodejs_package_manager_path": "npm", &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
"settings.editor.selected.configurable": "consents", &quot;settings.editor.selected.configurable&quot;: &quot;consents&quot;,
"to.speed.mode.migration.done": "true", &quot;to.speed.mode.migration.done&quot;: &quot;true&quot;,
"vue.rearranger.settings.migration": "true" &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
}]]></component> }</component>
<component name="RunManager"> <component name="RunManager">
<configuration default="true" type="AppleRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" IS_LOCATION_SIMULATION_SUPPORTED="false" IS_LOCATION_SIMULATION_ALLOWED="true" APPLICATION_LANGUAGE="IDELaunchSchemeLanguageUseSystemLanguage" APPLICATION_REGION="" DEVELOPMENT_TEAM="${TEAM_ID}" MAKE_ACTIVE="TRUE" SHOULD_DEBUG_EXTENSIONS="false"> <configuration default="true" type="AppleRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" IS_LOCATION_SIMULATION_SUPPORTED="false" IS_LOCATION_SIMULATION_ALLOWED="true" APPLICATION_LANGUAGE="IDELaunchSchemeLanguageUseSystemLanguage" APPLICATION_REGION="" DEVELOPMENT_TEAM="${TEAM_ID}" MAKE_ACTIVE="TRUE" SHOULD_DEBUG_EXTENSIONS="false">
<embedded_app_extension_list /> <embedded_app_extension_list />

View File

@@ -11,7 +11,7 @@
<meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0"> <meta http-equiv="Expires" content="0">
<title>Recipe App - Modular</title> <title>Recipe App - Modular</title>
<link rel="manifest" href="./manifest.webmanifest?v=20260406-63"> <link rel="manifest" href="./manifest.webmanifest?v=20260407-66">
<link rel="icon" type="image/png" sizes="192x192" href="./icons/icon-192.png"> <link rel="icon" type="image/png" sizes="192x192" href="./icons/icon-192.png">
<link rel="apple-touch-icon" href="./icons/apple-touch-icon.png"> <link rel="apple-touch-icon" href="./icons/apple-touch-icon.png">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
@@ -524,7 +524,7 @@
</div> </div>
<script> <script>
const APP_ASSET_VERSION = '20260406-63'; const APP_ASSET_VERSION = '20260407-66';
const APP_VERSION_STORAGE_KEY = 'recipe-app-asset-version'; const APP_VERSION_STORAGE_KEY = 'recipe-app-asset-version';
const APP_VERSION_QUERY_KEY = 'appv'; const APP_VERSION_QUERY_KEY = 'appv';
@@ -558,7 +558,7 @@
})(); })();
</script> </script>
<script type="module"> <script type="module">
const appVersion = window.__APP_ASSET_VERSION__ || '20260406-63'; const appVersion = window.__APP_ASSET_VERSION__ || '20260407-66';
const recoveryKey = `recipe-app-recovery-${appVersion}`; const recoveryKey = `recipe-app-recovery-${appVersion}`;
function renderBootstrapError(message) { function renderBootstrapError(message) {

View File

@@ -378,12 +378,6 @@ function renderDayContent(state) {
entries.forEach((entry) => { entries.forEach((entry) => {
if (entry?.recipeId && RECIPES[entry.recipeId]) slotKcal += computeEntryNutrition(entry).kcal; if (entry?.recipeId && RECIPES[entry.recipeId]) slotKcal += computeEntryNutrition(entry).kcal;
}); });
const kcalBadge = slotKcal > 0
? `<span class="text-[10px] font-semibold text-[#f2efe8] tabular-nums shrink-0 ml-auto">${slotKcal} kcal</span>`
: '';
const countLabel = entries.length > 1
? `<span class="text-[10px] font-semibold text-gray-400 tabular-nums shrink-0">${entries.length} dania</span>`
: '';
const entryCards = entries.map((entry) => { const entryCards = entries.map((entry) => {
const recipe = entry && entry.recipeId ? RECIPES[entry.recipeId] : null; const recipe = entry && entry.recipeId ? RECIPES[entry.recipeId] : null;
@@ -427,44 +421,36 @@ function renderDayContent(state) {
</div>`; </div>`;
}).join(''); }).join('');
if (isSkipped) { const addBtn = `<button type="button" class="planner-add-meal w-7 h-7 rounded-full border border-[#444442] text-[#9b978f] flex items-center justify-center shrink-0" data-slot-id="${slot.id}" aria-label="Dodaj przepis"><i class="fas fa-plus text-[10px]"></i></button>`;
return `
<div class="rounded-xl bg-[#393937] overflow-hidden opacity-60" style="background:#393937 !important; box-shadow:0 2px 8px rgba(0,0,0,0.25);" data-slot-id="${slot.id}">
<div class="flex items-center gap-2 px-3 py-2 border-b border-[#444442] bg-[#393937]" style="background:#393937 !important;">
<i class="fas ${slot.icon} w-7 text-center text-[13px] text-[#7d7a74] shrink-0" aria-hidden="true"></i>
<span class="text-[13px] font-semibold text-[#9b978f] truncate min-w-0 flex-1">${slot.label}</span>
</div>
<div class="p-2.5 flex items-center justify-between">
<span class="text-xs text-[#9b978f] italic"><i class="fas fa-forward text-[9px] mr-1.5"></i>Pominięto</span>
<button type="button" class="planner-unskip text-[11px] font-semibold text-[#9b978f] hover:text-[#ddd6ca] px-2 py-1 rounded-lg hover:bg-[#3a3a37] transition-colors" data-slot-id="${slot.id}">Cofnij</button>
</div>
</div>`;
}
const addLabel = entries.length === 0 ? 'Dodaj przepis' : 'Dodaj kolejny'; const kcalPill = slotKcal > 0
const addClasses = entries.length === 0 ? `<span class="text-[10px] font-semibold tabular-nums shrink-0 px-2 py-0.5 rounded-full" style="background:#2d2e2b; color:#d7d2c8;">${slotKcal} kcal</span>`
? 'planner-add-meal flex-1 py-2 rounded-lg border border-dashed border-[#444442] text-[13px] font-semibold text-[#d7d2c8] hover:bg-[#3a3a37] hover:border-[#6d6c67] transition-colors'
: 'planner-add-meal w-full py-1.5 rounded-lg border border-dashed border-[#444442] text-xs font-semibold text-[#d7d2c8] hover:bg-[#3a3a37] hover:border-[#6d6c67] transition-colors';
const skipBtn = entries.length === 0
? `<button type="button" class="planner-skip-meal shrink-0 py-2 px-3 rounded-lg text-[11px] font-semibold text-[#9b978f] hover:text-[#ddd6ca] hover:bg-[#3a3a37] transition-colors" data-slot-id="${slot.id}"><i class="fas fa-forward text-[9px] mr-1"></i>Pomijam</button>`
: ''; : '';
const bottomRow = entries.length === 0 const filledCard = `
? `<div class="flex gap-2">${`<button type="button" class="${addClasses}" data-slot-id="${slot.id}"><i class="fas fa-plus text-[10px] mr-1 opacity-70" aria-hidden="true"></i>${addLabel}</button>`}${skipBtn}</div>` <div class="rounded-xl bg-[#393937] overflow-hidden" style="background:#393937 !important; box-shadow:0 2px 8px rgba(0,0,0,0.25);" data-slot-id="${slot.id}">
: `<button type="button" class="${addClasses}" data-slot-id="${slot.id}"><i class="fas fa-plus text-[10px] mr-1 opacity-70" aria-hidden="true"></i>${addLabel}</button>`; <div class="flex items-center gap-2 px-3 py-2.5 bg-[#393937]" style="background:#393937 !important;">
<i class="fas ${slot.icon} w-7 text-center text-[13px] text-[#9b978f] shrink-0" aria-hidden="true"></i>
<span class="text-[13px] font-semibold text-[#ddd6ca] truncate min-w-0">${slot.label}</span>
<span class="ml-auto"></span>
${kcalPill}
${addBtn}
</div>
${entries.length > 0 ? `<div class="px-2.5 pb-2.5 space-y-2 border-t border-[#444442]" style="padding-top:0.625rem;">${entryCards}</div>` : ''}
</div>`;
if (entries.length > 0) return filledCard;
return ` return `
<div class="rounded-xl bg-[#393937] overflow-hidden" style="background:#393937 !important; box-shadow:0 2px 8px rgba(0,0,0,0.25);" data-slot-id="${slot.id}"> <div class="rounded-xl bg-[#393937] overflow-hidden" style="background:#393937 !important; box-shadow:0 2px 8px rgba(0,0,0,0.25);" data-slot-id="${slot.id}">
<div class="flex items-center gap-2 px-3 py-2 border-b border-[#444442] bg-[#393937]" style="background:#393937 !important;"> <div class="flex items-center gap-2 px-3 py-2.5">
<i class="fas ${slot.icon} w-7 text-center text-[13px] text-[#9b978f] shrink-0" aria-hidden="true"></i> <i class="fas ${slot.icon} w-7 text-center text-[13px] text-[#9b978f] shrink-0" aria-hidden="true"></i>
<span class="text-[13px] font-semibold text-[#ddd6ca] truncate min-w-0 flex-1">${slot.label}</span> <span class="text-[13px] font-semibold text-[#ddd6ca] truncate min-w-0">${slot.label}</span>
${countLabel} <span class="ml-auto"></span>
${kcalBadge} ${addBtn}
</div> </div>
<div class="p-2.5 space-y-2"> <div class="px-3 pb-2.5 -mt-0.5">
${entryCards} <p class="text-[11px] text-[#7d7a74] italic pl-9">Zaplanuj posiłek</p>
${bottomRow}
</div> </div>
</div>`; </div>`;
}).join(''); }).join('');