Skip to content

Commit

Permalink
Support pasting images
Browse files Browse the repository at this point in the history
  • Loading branch information
reaper47 committed Jul 22, 2024
1 parent 6e2f441 commit 6148ae6
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 3 deletions.
2 changes: 1 addition & 1 deletion internal/server/handlers_recipes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ func TestHandlers_Recipes_Edit(t *testing.T) {
`<title hx-swap-oob="true">Edit Chicken Jersey | Recipya</title>`,
`<input required type="text" name="title" placeholder="Title of the recipe*" autocomplete="off" class="input w-full btn-ghost text-center" value="Chicken Jersey">`,
`<div id="media-container" class="grid grid-flow-col grid-cols-7 w-full text-center border-gray-700 md:grid-cols-6 md:col-span-3 md:border-r"><div class="buttons-container flex flex-col gap-1 col-span-2 md:col-span-1 p-1"><button id="media-button-1" type="button" class="btn btn-sm btn-ghost btn-active" onclick="switchMedia(event)">Media 1</button> <button id="add-media-button" type="button" class="btn btn-sm btn-ghost" onclick="addMedia(event)"><svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 hover:text-red-600" fill="none" viewBox="0 0 24 24" width="24px" height="24px" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle> <line x1="12" y1="8" x2="12" y2="16"></line> <line x1="8" y1="12" x2="16" y2="12"></line></svg>Add</button></div><div id="media" class="col-span-5"><label id="media-1" class=""><img alt="" class="object-cover mb-2 w-full max-h-[39rem]" src=""> <span class="grid gap-1 max-w-sm" style="margin: auto auto 0.25rem;"><div class="mr-1"><input type="file" accept="image/*,video/*" name="images" class="file-input file-input-sm file-input-bordered w-full max-w-sm" value="/data/images/` + baseRecipe.Images[0].String() + `.webp" _="on dragover or dragenter halt the event then set the target's style.background to 'lightgray' on dragleave or drop set the target's style.background to '' on drop or change make an FileReader called reader then if event.dataTransfer get event.dataTransfer.files[0] else get event.target.files[0] end then if it.type.startsWith('video')`,
`after previous <img/> then add .hidden to previous <img/> else set {src: window.URL.createObjectURL(it)} on previous <img/> end then remove .hidden from me.parentElement.parentElement.querySelectorAll('button') then add .hidden to the parentElement of me"><div class="divider">OR</div><span class="hidden input-error"></span><div class="flex"><input type="url" placeholder="Enter the URL of an image" class="input input-bordered input-sm w-full max-w-sm mr-1"> <button type="button" class="btn btn-sm" hx-get="/fetch" hx-vals="js:{url: event.target.previousElementSibling.value}" hx-swap="none" _="on htmx:afterRequest if event.detail.successful then set a to first in event.target.parentElement.parentElement.children then call updateMediaFromFetch(a, event.detail.xhr.responseURL) end">Fetch</button></div></div><button type="button" class="btn btn-sm btn-error btn-outline hidden" onclick="deleteMedia(event)">Delete</button></span></label> </div>`,
`after previous <img/> then add .hidden to previous <img/> else set {src: window.URL.createObjectURL(it)} on previous <img/> end then remove .hidden from me.parentElement.parentElement.querySelectorAll('button') then add .hidden to the parentElement of me"><div class="divider">OR</div><span class="hidden input-error"></span><div class="flex"><input type="url" placeholder="Enter the URL of an image" class="input input-bordered input-sm w-full max-w-sm mr-1"> <button type="button" class="btn btn-sm" hx-get="/fetch" hx-vals="js:{url: event.target.previousElementSibling.value}" hx-swap="none" _="on htmx:afterRequest if event.detail.successful then set a to first in event.target.parentElement.parentElement.children then call updateMediaFromFetch(a, event.detail.xhr.responseURL) end">Fetch</button></div><div _="on load if not navigator.clipboard hide me"><div class="divider">OR</div><button type="button" class="btn btn-sm" onclick="pasteImage(event)">Paste copied image</button></div></div><button type="button" class="btn btn-sm btn-error btn-outline hidden" onclick="deleteMedia(event)">Delete</button></span></label> </div>`,
`<input type="text" list="categories" name="category" class="input input-bordered input-sm w-48 md:w-36 lg:w-48" placeholder="Breakfast" autocomplete="off" value="american"> <datalist id="categories"><option>breakfast</option><option>lunch</option><option>dinner</option></datalist>`,
`<input type="number" min="1" name="yield" class="input input-bordered input-sm w-24 md:w-20 lg:w-24" value="12">`,
`<input type="text" placeholder="Source" name="source" class="input input-bordered input-sm md:w-28 lg:w-40 xl:w-44" value="https://example.com/recipes/yummy"`,
Expand Down
2 changes: 1 addition & 1 deletion web/components/layouts.templ
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ templ head(title string) {
<meta name="theme-color" content="#ffffff"/>
<script src="https://unpkg.com/htmx.org@2.0.0" integrity="sha384-wS5l5IKJBvK6sPTKa2WZ1js3d947pvWXbPJ1OmWfEuxLgeHcEbjUUA5i9V5ZkpCw" crossorigin="anonymous"></script>
<script src="https://unpkg.com/hyperscript.org@0.9.11"></script>
<script src="https://unpkg.com/htmx.org/dist/ext/ws.js"></script>
<script src="https://unpkg.com/htmx-ext-ws@2.0.0/ws.js"></script>
<script defer>
const cookbooksPattern = new RegExp("^/cookbooks/\\d+(/recipes/search.*)?$");
const cookbooksSharePattern = new RegExp("^/c/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
Expand Down
38 changes: 38 additions & 0 deletions web/components/recipes.templ
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,10 @@ templ addRecipeManual(data *templates.ViewRecipeData) {
Fetch
</button>
</div>
<div _="on load if not navigator.clipboard hide me">
<div class="divider">OR</div>
<button type="button" class="btn btn-sm" onclick="pasteImage(event)">Paste copied image</button>
</div>
</div>
<button type="button" class="hidden btn btn-sm btn-error btn-outline" onclick="deleteMedia(event)">
Delete
Expand Down Expand Up @@ -1070,6 +1074,32 @@ templ loadRecipesManualScripts() {

clone.querySelector(el).focus();
}

async function pasteImage(event) {
try {
const clipboardItems = await navigator.clipboard.read();
clipboardItems.forEach(async (item) => {
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});

const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
const file = new File([blob], uuid, { type: blob.type });

const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);

const input = event.target.parentElement.parentElement.querySelector("input[type=file]");
input.files = dataTransfer.files;
input.dispatchEvent(new Event('change'));
})
} catch (err) {
console.error(err.name, err.message);
alert("No image in clipboard or ould not paste image.");
}
}
</script>
}

Expand Down Expand Up @@ -1198,6 +1228,10 @@ templ editRecipe(data *templates.ViewRecipeData) {
Fetch
</button>
</div>
<div _="on load if not navigator.clipboard hide me">
<div class="divider">OR</div>
<button type="button" class="btn btn-sm" onclick="pasteImage(event)">Paste copied image</button>
</div>
</div>
<button type="button" class="hidden btn btn-sm btn-error btn-outline" onclick="deleteMedia(event)">
Delete
Expand Down Expand Up @@ -1261,6 +1295,10 @@ templ editRecipe(data *templates.ViewRecipeData) {
Fetch
</button>
</div>
<div _="on load if not navigator.clipboard hide me">
<div class="divider">OR</div>
<button type="button" class="btn btn-sm" onclick="pasteImage(event)">Paste copied image</button>
</div>
</div>
<button
type="button"
Expand Down

0 comments on commit 6148ae6

Please sign in to comment.