Skip to content

Commit

Permalink
Finish web share
Browse files Browse the repository at this point in the history
  • Loading branch information
reaper47 committed Jul 20, 2024
1 parent d078835 commit a1d8405
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .idea/dataSources.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/website/content/about/changelog/v1.3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ weight: 1
## Added

- [EMOJI] **Bypass Guide option**: You may now bypass the guide and go straight to the login page when anonymous by setting the `server.bypassGuide` configuration variable or the `RECIPYA_SERVER_BYPASS_GUIDE` environment variable to `true`. You may also do so from the settings.
- [EMOJI] **Share**: It's now possible to share to multiple installed apps, e.g. WhatsApp, Gmail and Telegram.

## Fixed

Expand Down
14 changes: 11 additions & 3 deletions internal/server/handlers_cookbooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"log/slog"
"net/http"
"strconv"
"strings"
)

func (s *Server) cookbooksHandler() http.HandlerFunc {
Expand Down Expand Up @@ -651,10 +652,17 @@ func (s *Server) cookbookSharePostHandler() http.HandlerFunc {
return
}

link = r.Host + link
if !strings.HasPrefix(link, "http") {
if r.TLS != nil {
link = "https://" + link
} else {
link = "http://" + link
}
}

slog.Info("Cookbook shared", userIDAttr, "share", share, "link", link)

_ = components.ShareLink(templates.Data{
Content: r.Host + link,
}).Render(r.Context(), w)
_ = components.ShareLink(templates.Data{Content: link}).Render(r.Context(), w)
}
}
4 changes: 2 additions & 2 deletions internal/server/handlers_cookbooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func TestHandlers_Cookbooks(t *testing.T) {
`<form id="cookbook-image-form-2" enctype="multipart/form-data" hx-swap="none" hx-put="/cookbooks/2/image" hx-trigger="change from:#cookbook-image-2">`,
`<form id="cookbook-image-form-3" enctype="multipart/form-data" hx-swap="none" hx-put="/cookbooks/3/image" hx-trigger="change from:#cookbook-image-3">`,
`<span class="three-dots-container indicator-item indicator-end badge badge-neutral rounded-md p-1 select-none cursor-pointer hover:bg-secondary" _="on mousedown openCookbookOptionsMenu(event)"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-three-dots-vertical" viewBox="0 0 16 16"><path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"></path></svg></span>`,
`<a id="cookbook_menu_share" hx-post="/cookbooks/1/share" hx-target="#share-dialog-result" _="on htmx:afterRequest from me if event.detail.successful call share_dialog.showModal()">`,
`<a id="cookbook_menu_share" hx-post="/cookbooks/1/share" hx-target="#share-dialog-result" _="on htmx:afterRequest from me if event.detail.successful if navigator.canShare set name to 'Cookbook: ' + document.querySelector('.card-body h2').textContent then set data to {title: name, text: name, url: document.querySelector('#share-dialog-result input').value} then call navigator.share(data) else call share_dialog.showModal() end">`,
`<a id="cookbook_menu_download" hx-get="/cookbooks/1/download">`,
`<a id="cookbook_menu_delete" hx-delete="/cookbooks/1" hx-swap="outerHTML" hx-target="closest .cookbook" hx-confirm="Are you sure you want to delete this cookbook? Its recipes will not be deleted.">`,
`<button class="btn btn-outline btn-sm" hx-get="/cookbooks/1?page=1" hx-target="#content" hx-trigger="mousedown" hx-push-url="/cookbooks/1" hx-swap="innerHTML show:window:top transition:true">Open</button>`,
Expand Down Expand Up @@ -811,7 +811,7 @@ func TestHandlers_Cookbooks_Share(t *testing.T) {

assertStatus(t, rr.Code, http.StatusOK)
assertStringsInHTML(t, getBodyHTML(rr), []string{
`<div class="grid grid-flow-col gap-2"><label><input type="url" value="` + strings.TrimPrefix(ts.URL, "http://") + `/c/33320755-82f9-47e5-bb0a-d1b55cbd3f7b" class="input input-bordered w-full" readonly="readonly"></label> <script type="text/javascript">function __templ_copyToClipboard`,
`<div class="grid grid-flow-col gap-2"><label><input type="url" value="` + ts.URL + `/c/33320755-82f9-47e5-bb0a-d1b55cbd3f7b" class="input input-bordered w-full" readonly="readonly"></label> <script type="text/javascript">function __templ_copyToClipboard`,
`{if (window.navigator.clipboard) { navigator.clipboard.writeText(text); copy_button.textContent = "Copied!"; copy_button.setAttribute("disabled", true); copy_button.classList.toggle(".btn-disabled"); } else { alert('Your browser does not support the clipboard feature. Please copy the link manually.'); }}</script><button id="copy_button" class="btn btn-neutral" title="Copy to clipboard" onClick="__templ_copyToClipboard`,
})
})
Expand Down
13 changes: 10 additions & 3 deletions internal/server/handlers_recipes.go
Original file line number Diff line number Diff line change
Expand Up @@ -1020,11 +1020,18 @@ func (s *Server) recipeSharePostHandler() http.HandlerFunc {
return
}

link = r.Host + link
if !strings.HasPrefix(link, "http") {
if r.TLS != nil {
link = "https://" + link
} else {
link = "http://" + link
}
}

slog.Info("Created share link", userIDAttr, "share", share, "link", link)

_ = components.ShareLink(templates.Data{
Content: r.Host + link,
}).Render(r.Context(), w)
_ = components.ShareLink(templates.Data{Content: link}).Render(r.Context(), w)
}
}

Expand Down
10 changes: 5 additions & 5 deletions internal/server/handlers_recipes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1300,7 +1300,7 @@ func TestHandlers_Recipes_Share(t *testing.T) {

assertStatus(t, rr.Code, http.StatusOK)
want := []string{
`<input type="url" value="` + strings.TrimPrefix(ts.URL, "http://") + `/r/33320755-82f9-47e5-bb0a-d1b55cbd3f7b" class="input input-bordered w-full" readonly="readonly"></label>`,
`<input type="url" value="` + ts.URL + `/r/33320755-82f9-47e5-bb0a-d1b55cbd3f7b" class="input input-bordered w-full" readonly="readonly"></label>`,
`<button id="copy_button" class="btn btn-neutral" title="Copy to clipboard" onClick="__templ_copyToClipboard`,
}
assertStringsInHTML(t, getBodyHTML(rr), want)
Expand All @@ -1321,7 +1321,7 @@ func TestHandlers_Recipes_Share(t *testing.T) {
`<title hx-swap-oob="true">` + recipe.Name + " | Recipya</title>",
`<button title="Toggle screen lock" _="on load if not navigator.wakeLock hide me end on click if wakeLock wakeLock.release() then add @d=`,
`<a href="/auth/login" class="btn btn-ghost">Log In</a> <a href="/auth/register" class="btn btn-ghost">Sign Up</a>`,
`<span class="text-center pb-2 print:w-full">Chicken Jersey</span>`,
`<span class="text-center pb-2 print:w-full" itemprop="name">Chicken Jersey</span>`,
`<button class="mr-2" title="Print recipe" _="on click print()">`,
`<img id="output" style="object-fit: cover" alt="Image of the recipe" class="w-full max-h-80 md:max-h-[34rem]" src="/static/img/recipes/placeholder.webp">`,
`<div class="badge badge-primary badge-outline">American</div>`,
Expand Down Expand Up @@ -1646,13 +1646,13 @@ func TestHandlers_Recipes_View(t *testing.T) {
`<title hx-swap-oob="true">` + r.Name + " | Recipya</title>",
`<button title="Toggle screen lock" _="on load if not navigator.wakeLock hide me end on click if wakeLock wakeLock.release() then add @d='M 12.276 18.55 v -0.748 a 4.79 4.79 0 0 1 1.463 -3.458 a 5.763 5.763 0 0 0 1.804 -4.21 a 5.821 5.821 0 0 0 -6.475 -5.778 c -2.779 0.307 -4.99 2.65 -5.146 5.448 a 5.82 5.82 0 0 0 1.757 4.503 a 4.906 4.906 0 0 1 1.5 3.495 v 0.747 a 1.44 1.44 0 0 0 1.44 1.439 h 2.218 a 1.44 1.44 0 0 0 1.44 -1.439 z m -1.058 0 c 0 0.209 -0.17 0.38 -0.38 0.38 h -2.22 c -0.21 0 -0.38 -0.171 -0.38 -0.38 v -0.748 c 0 -1.58 -0.664 -3.13 -1.822 -4.254 A 4.762 4.762 0 0 1 4.98 9.863 c 0.127 -2.289 1.935 -4.204 4.205 -4.455 a 4.762 4.762 0 0 1 5.3 4.727 a 4.714 4.714 0 0 1 -1.474 3.443 a 5.853 5.853 0 0 0 -1.791 4.225 v 0.746 z M 11.45 20.51 H 8.006 a 0.397 0.397 0 1 0 0 0.795 h 3.444 a 0.397 0.397 0 1 0 0 -0.794 z M 11.847 22.162 a 0.397 0.397 0 0 0 -0.397 -0.397 H 8.006 a 0.397 0.397 0 1 0 0 0.794 h 3.444 c 0.22 0 0.397 -0.178 0.397 -0.397 z z z z z z z z M 10.986 23.416 H 8.867 a 0.397 0.397 0 1 0 0 0.794 h 1.722 c 0.22 0 0.397 -0.178 0.397 -0.397 z' to #icon-bulb else call initWakeLock() then add @d='M12.276 18.55v-.748a4.79 4.79 0 0 1 1.463-3.458 5.763 5.763 0 0 0 1.804-4.21 5.821 5.821 0 0 0-6.475-5.778c-2.779.307-4.99 2.65-5.146 5.448a5.82 5.82 0 0 0 1.757 4.503 4.906 4.906 0 0 1 1.5 3.495v.747a1.44 1.44 0 0 0 1.44 1.439h2.218a1.44 1.44 0 0 0 1.44-1.439zm-1.058 0c0 .209-.17.38-.38.38h-2.22c-.21 0-.38-.171-.38-.38v-.748c0-1.58-.664-3.13-1.822-4.254A4.762 4.762 0 0 1 4.98 9.863c.127-2.289 1.935-4.204 4.205-4.455a4.762 4.762 0 0 1 5.3 4.727 4.714 4.714 0 0 1-1.474 3.443 5.853 5.853 0 0 0-1.791 4.225v.746zM11.45 20.51H8.006a.397.397 0 1 0 0 .795h3.444a.397.397 0 1 0 0-.794zM11.847 22.162a.397.397 0 0 0-.397-.397H8.006a.397.397 0 1 0 0 .794h3.444c.22 0 .397-.178.397-.397zM.397 10.125h2.287a.397.397 0 1 0 0-.794H.397a.397.397 0 1 0 0 .794zM19.456 9.728a.397.397 0 0 0-.397-.397h-2.287a.397.397 0 1 0 0 .794h2.287c.22 0 .397-.178.397-.397zM9.331.397v2.287a.397.397 0 1 0 .794 0V.397a.397.397 0 1 0-.794 0zM16.045 2.85 14.43 4.465a.397.397 0 1 0 .561.561l1.617-1.617a.397.397 0 1 0-.562-.56zM5.027 14.429a.397.397 0 0 0-.56 0l-1.618 1.616a.397.397 0 1 0 .562.562l1.617-1.617a.397.397 0 0 0 0-.561zM4.466 5.027a.396.396 0 0 0 .562 0 .397.397 0 0 0 0-.56L3.41 2.848a.397.397 0 1 0-.561.561zM16.045 16.607a.396.396 0 0 0 .562 0 .397.397 0 0 0 0-.562L14.99 14.43a.397.397 0 1 0-.561.56zM10.986 23.416a.397.397 0 0 0-.397-.397H8.867a.397.397 0 1 0 0 .794h1.722c.22 0 .397-.178.397-.397z' to #icon-bulb end"><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"><path id="icon-bulb" d="M12.276 18.55v-.748a4.79 4.79 0 0 1 1.463-3.458 5.763 5.763 0 0 0 1.804-4.21 5.821 5.821 0 0 0-6.475-5.778c-2.779.307-4.99 2.65-5.146 5.448a5.82 5.82 0 0 0 1.757 4.503 4.906 4.906 0 0 1 1.5 3.495v.747a1.44 1.44 0 0 0 1.44 1.439h2.218a1.44 1.44 0 0 0 1.44-1.439zm-1.058 0c0 .209-.17.38-.38.38h-2.22c-.21 0-.38-.171-.38-.38v-.748c0-1.58-.664-3.13-1.822-4.254A4.762 4.762 0 0 1 4.98 9.863c.127-2.289 1.935-4.204 4.205-4.455a4.762 4.762 0 0 1 5.3 4.727 4.714 4.714 0 0 1-1.474 3.443 5.853 5.853 0 0 0-1.791 4.225v.746zM11.45 20.51H8.006a.397.397 0 1 0 0 .795h3.444a.397.397 0 1 0 0-.794zM11.847 22.162a.397.397 0 0 0-.397-.397H8.006a.397.397 0 1 0 0 .794h3.444c.22 0 .397-.178.397-.397zM.397 10.125h2.287a.397.397 0 1 0 0-.794H.397a.397.397 0 1 0 0 .794zM19.456 9.728a.397.397 0 0 0-.397-.397h-2.287a.397.397 0 1 0 0 .794h2.287c.22 0 .397-.178.397-.397zM9.331.397v2.287a.397.397 0 1 0 .794 0V.397a.397.397 0 1 0-.794 0zM16.045 2.85 14.43 4.465a.397.397 0 1 0 .561.561l1.617-1.617a.397.397 0 1 0-.562-.56zM5.027 14.429a.397.397 0 0 0-.56 0l-1.618 1.616a.397.397 0 1 0 .562.562l1.617-1.617a.397.397 0 0 0 0-.561zM4.466 5.027a.396.396 0 0 0 .562 0 .397.397 0 0 0 0-.56L3.41 2.848a.397.397 0 1 0-.561.561zM16.045 16.607a.396.396 0 0 0 .562 0 .397.397 0 0 0 0-.562L14.99 14.43a.397.397 0 1 0-.561.56zM10.986 23.416a.397.397 0 0 0-.397-.397H8.867a.397.397 0 1 0 0 .794h1.722c.22 0 .397-.178.397-.397z"></path></svg></button>`,
`<button class="ml-2" title="Edit recipe" hx-get="/recipes/1/edit" hx-push-url="true" hx-target="#content" hx-swap="innerHTML transition:true"><svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 hover:text-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"></path></svg></button>`,
`<span class="text-center pb-2 print:w-full">Chicken Jersey</span>`,
`<button class="mr-2" title="Share recipe" hx-post="/recipes/1/share" hx-target="#share-dialog-result" _="on htmx:afterRequest from me if event.detail.successful call share_dialog.showModal()">`,
`<span class="text-center pb-2 print:w-full" itemprop="name">Chicken Jersey</span>`,
`<button class="mr-2" title="Share recipe" hx-post="/recipes/1/share" hx-target="#share-dialog-result" _="on htmx:afterRequest from me if event.detail.successful if navigator.canShare set name to document.querySelector('[itemprop=name]').textContent then set data to {title: name, text: name, url: document.querySelector('#share-dialog-result input').value} then call navigator.share(data) else call share_dialog.showModal() end">`,
`<button class="mr-2" title="Print recipe" _="on click print()">`,
`<button class="mr-2" hx-delete="/recipes/1" hx-swap="none" title="Delete recipe" hx-confirm="Are you sure you wish to delete this recipe?" hx-indicator="#fullscreen-loader">`,
`<img id="output" style="object-fit: cover" alt="Image of the recipe" class="w-full max-h-80 md:max-h-[34rem]" src="/static/img/recipes/placeholder.webp">`,
`<div class="badge badge-primary badge-outline">American</div>`,
`<button class="mr-2" title="Share recipe" hx-post="/recipes/1/share" hx-target="#share-dialog-result" _="on htmx:afterRequest from me if event.detail.successful call share_dialog.showModal()"><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">`,
`<button class="mr-2" title="Share recipe" hx-post="/recipes/1/share" hx-target="#share-dialog-result" _="on htmx:afterRequest from me if event.detail.successful if navigator.canShare set name to document.querySelector('[itemprop=name]').textContent then set data to {title: name, text: name, url: document.querySelector('#share-dialog-result input').value} then call navigator.share(data) else call share_dialog.showModal() end"><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">`,
`<form autocomplete="off" _="on submit halt the event" class="print:hidden"><label class="form-control w-full"><div class="label p-0"><span class="label-text">Servings</span></div><input id="yield" type="number" min="1" name="yield" value="2" class="input input-bordered input-sm w-24" hx-get="/recipes/1/scale" hx-trigger="input" hx-target="#ingredients-instructions-container"></label></form>`,
`<a class="btn btn-sm btn-outline no-underline print:hidden" href="https://www.allrecipes.com/recipe/10813/best-chocolate-chip-cookies/" target="_blank">Source</a>`,
`<textarea class="textarea w-full h-full resize-none" readonly>This is the most delicious recipe!</textarea>`,
Expand Down
10 changes: 9 additions & 1 deletion web/components/cookbooks.templ
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,15 @@ templ cookbooksIndex(data templates.Data) {
id="cookbook_menu_share"
hx-post="/cookbooks/1/share"
hx-target="#share-dialog-result"
_="on htmx:afterRequest from me if event.detail.successful call share_dialog.showModal()"
_="on htmx:afterRequest from me
if event.detail.successful
if navigator.canShare
set name to 'Cookbook: ' + document.querySelector('.card-body h2').textContent then
set data to {title: name, text: name, url: document.querySelector('#share-dialog-result input').value} then
call navigator.share(data)
else
call share_dialog.showModal()
end"
>
@iconShare()
Share
Expand Down
10 changes: 6 additions & 4 deletions web/components/recipes.templ
Original file line number Diff line number Diff line change
Expand Up @@ -1945,7 +1945,7 @@ templ viewRecipe(data *templates.ViewRecipeData, isAuthenticated bool) {
</button>
}
</span>
<span class="text-center pb-2 print:w-full">{ data.Recipe.Name }</span>
<span class="text-center pb-2 print:w-full" itemprop="name">{ data.Recipe.Name }</span>
<span class="grid grid-flow-col place-items-center pb-2 print:hidden">
if data.Share.IsShared {
if !data.Share.IsFromHost {
Expand All @@ -1966,10 +1966,12 @@ templ viewRecipe(data *templates.ViewRecipeData, isAuthenticated bool) {
hx-target="#share-dialog-result"
_="on htmx:afterRequest from me
if event.detail.successful
if no navigator.canShare
call share_dialog.showModal()
if navigator.canShare
set name to document.querySelector('[itemprop=name]').textContent then
set data to {title: name, text: name, url: document.querySelector('#share-dialog-result input').value} then
call navigator.share(data)
else
alert('fuck')
call share_dialog.showModal()
end"
>
@iconShare()
Expand Down

0 comments on commit a1d8405

Please sign in to comment.