Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preview version of recipe categories #368

Merged
merged 23 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": {}
},
"tasks": {
"test": "yarn && npx playwright install chromium firefox webkit && yarn dev && npx playwright test",
"test": "yarn && npx playwright install chromium webkit && yarn dev && npx playwright test",
"launch": "yarn && yarn dev"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:

- name: Run Playwright tests
run: |
npx playwright install chromium firefox webkit
npx playwright install chromium webkit
HOME=/root npx playwright test
- name: Create test summary
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Sharp Cooking leverages [Playwright](https://playwright.dev/) for end to end tes

Install playwright browsers:
```powershell
npx playwright install chromium firefox webkit
npx playwright install chromium webkit
```

Run tests locally:
Expand Down
13 changes: 5 additions & 8 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const config: PlaywrightTestConfig = {
trace: 'on-first-retry',
video: 'off',
screenshot: 'only-on-failure',
contextOptions: {
serviceWorkers: "block"
}
},

/* Configure projects for major browsers */
Expand All @@ -62,22 +65,16 @@ const config: PlaywrightTestConfig = {
...devices['Desktop Safari'],
},
},
{
name: 'firefox',
use: {
...devices['DeskDesktop Firefox'],
},
},
{
name: 'Mobile Chrome',
use: {
...devices['Pixel 5'],
...devices['Pixel 7'],
},
},
{
name: 'Mobile Safari',
use: {
...devices['iPhone 12'],
...devices['iPhone 15'],
},
},
],
Expand Down
25 changes: 23 additions & 2 deletions public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@
"aiModelName": "AI Model Name",
"aiModelNameDescription": "The name of the OpenAI model to use for the AI Chat service.",
"editInSingleTextArea": "Enable simplified recipe editor",
"editInSingleTextAreaDescription": "Use one text area to edit ingredients and another for steps."
"editInSingleTextAreaDescription": "Use one text area to edit ingredients and another for steps.",
"enableCategoryDisplay": "Enable Category Display",
"enableCategoryDisplayDescription": "When enabled, show a list of categories on the main page.",
"categories": "Categories",
"categoriesDescription": "Maintain list of categories"
},
"recipe": {
"id": {
Expand Down Expand Up @@ -134,7 +138,9 @@
"sugar": "Sugar (g)",
"protein": "Protein (g)",
"changeLanguage": "Change Language",
"changeLanguageTitle": "Change recipe language"
"changeLanguageTitle": "Change recipe language",
"category": "Category",
"selectCategory": "Select category..."
},
"gallery": {
"recipeImage": "Recipe Image"
Expand Down Expand Up @@ -247,6 +253,21 @@
"chat": {
"abortError": "Ok. I won't answer that question.",
"unableToAnswer": "I'm sorry, I'm unable to answer that question right now."
},
"categories": {
"title": "Categories",
"newTitle": "New Category",
"selectImage": "Select an image...",
"delete": "Delete...",
"edit": "Edit...",
"deleteModalTitle": "Delete this category?",
"deleteModalBody": "Are you sure? This action cannot be undone.",
"deleteYes": "Yes, delete",
"categoryDeleted": "Category deleted successfully.",
"categoryDeleteFailed": "Failed to delete the category.",
"processImage1": "Compressing image...",
"processImage2": "Still working on the image. This may take a while",
"selectAnItem": "Please select an item."
}
},
"initialRecipes": [
Expand Down
25 changes: 23 additions & 2 deletions public/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@
"aiModelName": "Nome do Modelo de IA",
"aiModelNameDescription": "O nome do modelo OpenAI a ser usado para o serviço de Chat de IA.",
"editInSingleTextArea": "Habilitar editor de receitas simplificado",
"editInSingleTextAreaDescription": "Use uma área de texto para editar os ingredientes e outra para os passos."
"editInSingleTextAreaDescription": "Use uma área de texto para editar os ingredientes e outra para os passos.",
"enableCategoryDisplay": "Ativar Categorias",
"enableCategoryDisplayDescription": "Quando ativado, mostra uma lista de categories na página principal.",
"categories": "Categorias",
"categoriesDescription": "Manter lista de categorias"
},
"recipe": {
"id": {
Expand Down Expand Up @@ -133,7 +137,9 @@
"sugar": "Açúcares (g)",
"protein": "Proteínas (g)",
"changeLanguage": "Alterar idioma",
"changeLanguageTitle": "Alterar idioma da receita"
"changeLanguageTitle": "Alterar idioma da receita",
"category": "Categoria",
"selectCategory": "Selecione categoria..."
},
"gallery": {
"recipeImage": "Imagem de Receita"
Expand Down Expand Up @@ -245,6 +251,21 @@
"chat": {
"abortError": "Ok. Eu não vou responder essa pergunta.",
"unableToAnswer": "Desculpe, eu não consigo responder sua pergunta no momento."
},
"categories": {
"title": "Categorias",
"newTitle": "Nova categoria",
"selectImage": "Selecione uma imagem...",
"delete": "Remover...",
"edit": "Editar...",
"deleteModalTitle": "Excluir esta categoria?",
"deleteYes": "Sim, exclua",
"deleteModalBody": "Essa ação não pode ser desfeita.",
"categoryDeleted": "Categoria excluída com sucesso.",
"categoryDeleteFailed": "Falhou em excluir a categoria",
"processImage1": "Comprimindo imagem...",
"processImage2": "Ainda processando. Isso pode demorar um pouco...",
"selectAnItem": "Selecione um item."
}
},
"initialRecipes": [
Expand Down
64 changes: 64 additions & 0 deletions src/components/AddButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<script setup lang="ts">
import { Menu, MenuButton, MenuItems, MenuItem } from "@headlessui/vue";
const props = defineProps<{
items: Array<{ name: string, text: string, action: () => void }>;
}>();
</script>

<template>
<Menu as="div" class="p-0 w-14 h-14 fixed bottom-6 right-6">
<div>
<MenuButton data-testid="add-menu-button" class="
w-12
h-12
m-1
rounded-full
bg-theme-primary
hover:bg-theme-secondary
focus:bg-theme-secondary
focus:shadow-lg
shadow-md
hover:shadow-lg
transition duration-150 ease-in-out
">
<svg viewBox="0 0 20 20" enable-background="new 0 0 20 20" class="w-6 h-6 inline-block">
<path fill="#FFFFFF" d="M16,10c0,0.553-0.048,1-0.601,1H11v4.399C11,15.951,10.553,16,10,16c-0.553,0-1-0.049-1-0.601V11H4.601
C4.049,11,4,10.553,4,10c0-0.553,0.049-1,0.601-1H9V4.601C9,4.048,9.447,4,10,4c0.553,0,1,0.048,1,0.601V9h4.399
C15.952,9,16,9.447,16,10z" />
</svg>
</MenuButton>
</div>

<transition enter-active-class="transition duration-100 ease-out" enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100" leave-active-class="transition duration-75 ease-in"
leave-from-class="transform scale-100 opacity-100" leave-to-class="transform scale-95 opacity-0">
<MenuItems class="
-top-2
transform
-translate-y-full
absolute
right-0
w-56
origin-top-right
bg-white
divide-y divide-gray-100
rounded-md
shadow-lg
ring-1 ring-black ring-opacity-5
focus:outline-none
">
<div class="px-1 py-1">
<MenuItem :key="child.name" v-for="child in props.items" v-slot="{ active }">
<button @click="child.action" :class="[
active ? 'bg-theme-secondary text-white' : 'text-gray-900',
'group flex w-full items-center rounded-md px-2 py-2 text-sm',
]">
{{ child.text }}
</button>
</MenuItem>
</div>
</MenuItems>
</transition>
</Menu>
</template>
32 changes: 32 additions & 0 deletions src/components/CategoryList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import { useTranslation } from "i18next-vue";
import { useState } from "../services/store";
import RecipeCard from "./RecipeCard.vue";
import { Category } from "../services/category";
import { getCategories } from "../services/dataService";
const router = useRouter();
const { t } = useTranslation();
const state = useState()!;
const categories = ref([] as Array<Category>);
onMounted(async () => {
categories.value = await getCategories();
});
function goToCategory(id: number) {
router.push(`/category/${id}`);
}
</script>

<template>
<div class="bg-white text-slate-900 dark:bg-theme-gray dark:text-white">
<div class="grid md:grid-cols-2 lg:grid-cols-3 my-4 gap-5">
<recipe-card v-for="category in categories" :title="category.name" :image="category.image"
:imageAvailable="category.image != undefined" :recipeCount="category.recipeCount"
@click="goToCategory(category.id)" :rating="0" />
</div>
</div>
</template>
109 changes: 109 additions & 0 deletions src/components/ConfigSwitch.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<script setup lang="ts">
import { ref, watch, onMounted } from "vue";
const props = defineProps<{
modelValue: boolean;
displayName: string;
displayDescription: string;
testId: string;
}>();
const emit = defineEmits<{
(e: "update:modelValue", value: boolean): void;
}>();
const localValue = ref(false);
watch(
() => props.modelValue,
(newValue: boolean) => {
localValue.value = newValue;
}
);
onMounted(() => {
localValue.value = props.modelValue;
});
function updateValue(value: boolean) {
emit("update:modelValue", value);
}
</script>

<template>
<div>
<span class="dark:text-white">{{ props.displayName }}</span>
<label :data-testid="props.testId" class="switch float-right align-middle">
<input :checked="localValue" type="checkbox" @change="evt => updateValue((evt.target as HTMLInputElement).checked)">
<span class="slider round"></span>
</label>
<div>
<span class="text-gray-500 text-sm">{{ props.displayDescription }}</span>
</div>
</div>
</template>

<style>
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 30px;
height: 17px;
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 13px;
width: 13px;
left: 2px;
bottom: 2px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked+.slider {
background-color: #2196F3;
}
input:focus+.slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked+.slider:before {
-webkit-transform: translateX(13px);
-ms-transform: translateX(13px);
transform: translateX(13px);
}
/* Rounded sliders */
.slider.round {
border-radius: 17px;
}
.slider.round:before {
border-radius: 50%;
}
</style>
Loading
Loading