Просмотр исходного кода

Create upload button for recipes

Lee Morgan 1 неделя назад
Родитель
Сommit
a2f081bd20
2 измененных файлов с 125 добавлено и 7 удалено
  1. 124 7
      src/routes/dashboard/+page.svelte
  2. 1 0
      src/routes/recipe/[recipeId]/+page.svelte

+ 124 - 7
src/routes/dashboard/+page.svelte

@@ -1,11 +1,52 @@
 <script>
+    import {notify} from "$lib/notifier.svelte.js";
+    import {goto} from "$app/navigation";
+
     let {data} = $props();
+    let uploadInput = $state();
+
+    const uploadRecipe = async ()=>{
+        const file = uploadInput.files[0];
+        uploadInput.value = "";
+        if(!file) return;
+
+        try{
+            const text = await file.text();
+            const response = await fetch("/recipe/new", {
+                method: "POST",
+                headers: {"Content-Type": "application/json"},
+                credentials: "include",
+                body: text
+            });
+
+            let responseData = await response.json();
+            if(!response.ok) return notify("error", responseData.msg);
+
+            notify("success", "Recipe added");
+            goto(`/recipe/${responseData.id}`);
+        }catch(e){
+            notify("error", "Failed to parse the recipe");
+        }
+    }
 </script>
 
 <div class="container">
     <div class="topbar">
         <h1>Recipes</h1>
-        <a href="/recipe/new" class="button">New Recipe</a>
+        <div class="share">
+            <button type="button" class="shareToggle" aria-haspopup="true">New Recipe</button>
+            <div class="shareMenu" role="menu">
+                <a href="/recipe/new" role="menuitem">Create</a>
+                <button role="menuitem" onclick={()=>{uploadInput.click()}}>Upload</button>
+                <input
+                    bind:this={uploadInput}
+                    onchange={uploadRecipe}
+                    type="file"
+                    accept=".json,application/json"
+                    hidden
+                >
+            </div>
+        </div>
     </div>
 
     <div class="recipes">
@@ -46,10 +87,87 @@
         min-width: 0;
     }
 
-    .button{
+    .shareToggle{
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        box-sizing: border-box;
+        border: none;
+        outline: none;
+        cursor: pointer;
         margin: 0;
+        background: var(--color-primary);
+        color: var(--color-text-on-primary);
+        border-radius: 6px;
+        padding: 0.6rem 1.2rem;
+        font-weight: 600;
+        font-size: 1rem;
+        line-height: 1.2;
+        white-space: nowrap;
+        text-decoration: none;
+        transition: background 0.15s ease, transform 0.05s ease;
+        font-family: inherit;
+    }
+
+    .shareToggle:hover{
+        background: var(--color-primary-hover);
+    }
+
+    .shareToggle:active{
+        transform: translateY(1px);
+    }
+
+    .share{
+        position: relative;
         flex-shrink: 0;
-        text-align: center;
+    }
+
+    .shareMenu{
+        position: absolute;
+        right: 0;
+        top: calc(100% + 0.4rem);
+        z-index: 10;
+        display: none;
+        flex-direction: column;
+        gap: 0.2rem;
+        min-width: 100%;
+        padding: 0.35rem;
+        background: var(--color-surface);
+        border: 1px solid var(--color-border);
+        border-radius: 8px;
+        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
+    }
+
+    .share:focus-within .shareMenu{
+        display: flex;
+    }
+
+    .shareMenu button,
+    .shareMenu a{
+        display: flex;
+        align-items: center;
+        box-sizing: border-box;
+        border: none;
+        outline: none;
+        cursor: pointer;
+        margin: 0;
+        width: 100%;
+        padding: 0.55rem 0.8rem;
+        background: transparent;
+        color: var(--color-text);
+        border-radius: 6px;
+        font-weight: 600;
+        font-size: 0.9rem;
+        line-height: 1.2;
+        text-align: left;
+        white-space: nowrap;
+        text-decoration: none;
+        font-family: inherit;
+    }
+
+    .shareMenu button:hover,
+    .shareMenu a:hover{
+        background: var(--color-surface-alt);
     }
 
     .recipes{
@@ -121,11 +239,10 @@
     }
 
     @media (pointer: coarse){
-        .button{
+        .shareToggle,
+        .shareMenu button,
+        .shareMenu a{
             min-height: 44px;
-            display: inline-flex;
-            align-items: center;
-            justify-content: center;
         }
     }
 </style>

+ 1 - 0
src/routes/recipe/[recipeId]/+page.svelte

@@ -29,6 +29,7 @@
             ingredients: data.recipe.ingredients,
             steps: data.recipe.steps,
             notes: data.recipe.notes,
+            private: data.recipe.private
         });
         const blob = new Blob([json], {type: "application/json"});
         const url = URL.createObjectURL(blob);