Modal navigation - backpage
store and sveltekit:in
attribute for anchors [syntax proposal]
#4560
Replies: 6 comments 10 replies
-
Has this moved at all ? |
Beta Was this translation helpful? Give feedback.
-
Damn, I'm completely lost on how to implement this. |
Beta Was this translation helpful? Give feedback.
-
If i may offer an alternative suggestion to handling modals - what if <!-- +layout.svelte -->
<main>
<slot />
</main>
<div id="modal-wrapper" >
<slot name="modal1" />
</div> Then the slot name could correspond to svelte components next to the layout file
The only thing left is to consider how we determine if/when modal1.svelte should be in the slot I suggest we could reuse the matcher concept either explicitly or tacitly - but it would probably need to be extended to get the full URL object //src/params/modal1.js
export function match(url) {
return url.seachParams.has("modal1QueryParam")
} Then each time the url changes we simply need to check the match function and if it returns true inject modal1 into the corresponding slot. Would this solution not solve most use cases for modals? While allowing the developer full control of how its positioned in the dom while using only existing svelte kit concepts. Let me know your thoughts |
Beta Was this translation helpful? Give feedback.
-
Is there any update on this? |
Beta Was this translation helpful? Give feedback.
-
One way I found currently to fake it is to direclty manipulate the browser's history myself. I have a page <script lang="ts">
import { enhance } from '$app/forms'
import type { PageData } from './$types'
export let data: PageData
$: href = data.mine ? '/profile' : `/users/${data.post.author.id}`
$: by = data.mine ? 'you' : data.post.author.name
let dialog: HTMLDialogElement
</script>
<h1 class="mb-3 font-bold">{data.post.title}</h1>
<textarea
class="w-full"
value={data.post.content}
readonly
/>
<p>
Post written by
<a
{href}
class="underline">{by}</a
>
</p>
<div class="mt-3 flex gap-3 empty:hidden">
{#if data.canUpdate}
<a
class="border p-3"
href={`/posts/${data.post.id}/edit`}>Update</a
>
{/if}
{#if data.canDelete}
<a
href={`/posts/${data.post.id}/delete`}
class="border border-red-500 p-3"
on:click|preventDefault={() => {
history.replaceState(null, '', `/posts/${data.post.id}/delete`)
dialog.showModal()
}}
>
Delete
</a>
<dialog
bind:this={dialog}
on:close={() => {
history.replaceState(null, '', `/posts/${data.post.id}`)
dialog.close()
}}
class="border p-10 shadow"
>
<form
action={`/posts/${data.post.id}/delete`}
method="post"
class="flex flex-col gap-3"
use:enhance
>
<div>Are you sure you want to delete this post?</div>
<input
type="hidden"
name="id"
value={data.post.id}
/>
<div class="flex gap-1">
<form method="dialog">
<button class="border p-3">Cancel</button>
</form>
<button
type="submit"
class="border border-red-500 p-3">Yes</button
>
</div>
</form>
</dialog>
{/if}
</div> And a <script lang="ts">
import { enhance } from '$app/forms'
import type { ActionData, PageData } from './$types'
export let data: PageData
export let form: ActionData
</script>
{#if form?.error}
<h1>{form?.error}</h1>
{/if}
<form
method="post"
class="flex flex-col gap-3"
use:enhance
>
<div>Are you sure you want to delete this post?</div>
<input
type="hidden"
name="id"
value={data.post.id}
/>
<div class="flex gap-1">
<a
href={`/posts/${data.post.id}`}
class="border p-3">Cancel</a
>
<button
type="submit"
class="border border-red-500 p-3">Yes</button
>
</div>
</form> You could easily refactor things to have a DeletePostForm.svelte component that you could then share between the dialog and the actual page. However with this solution it won't call any potential load function you may have on the delete page. You could call that manually though. |
Beta Was this translation helpful? Give feedback.
-
Is there any official update to this topic? The solution from @CapitaineToinon looks promising but it also looks like I have a write a lot of code twice 🙈 |
Beta Was this translation helpful? Give feedback.
-
Describe the problem
Because Rich in the video said that Modal navigation is needed before SvelteKit 1.0 - https://youtu.be/s6a1pbTVcUs?t=1642
Describe the proposed solution
That's the idea of syntax -
backpage
store andsveltekit:in
attribute.Need, for example, to open a modal page visible above the background page (screenshots at the bottom of this issue).
Behavior similar to the page shown in layout slot, but not identical. Page in page.
Opening modal
Click the link - the url in the address bar changes to
"/page/subpage1"
and its contents land in<slot/>
in"/page"
-"/page"
content remains and"/page/subpage1"
content loads into<slot/>
in"/page"
.When open modal (after click the anchor):
page
store ("/page/subpage1"
) is the modal.backpage
store ("/page"
) is the page, which is in the background.When not open modal (before click the anchor):
page
store ("/page"
) is the only open url on the whole page, there is no modal.backpage
store ("/page"
) is the same, the only open url on the full page.(that's why it' worth looking for a better name instead of
backpage
, which takes into account when the "background" is on top...)IMPORTANT: The value of
$backpage.url
is the same as$page.url
when no Modal is displayed. This allows you to navigate the same way from"/page"
and from"/page/subpage1"
- and here and here the identical button and anchor tag works.Example: the code for the "next" button
<a href="/page/subpage2" sveltekit:in={$backpage.url.pathname}>link</a>
- the only difference is the href value, all the rest of this element is unchanged relative to the first subpage opening button.Modal would be loaded without its layout. backpage would be instead of its own layout.
Closing modal
Click the link - back to
"/page"
- a simple link that simply changes the url in the address bar and removes"/page/subpage1"
from<slot/>
in"/page"
.Because there is no
sveltekit:in
attribute in the anchor, the link behaves as if it opened a regular page, so it removes all modals that are unnecessary.Optional (you can live without them)
sveltekit:in
with no value - takes the currentbackpage
for simplicity.</slot>
in"/page"
, maybe a fallback display as an extra layer above"/page"
- that is, as if it were ready for modal.sveltekit:in
- e.g.sveltekit:in={[path1, path2, path3]}
and storebackpages
with this array.Algorithm: in the
backpages
are all the pages except the one most "on top".Example: an image from a comment, opened from an image from a post, opened from a Facebook wall - wall and image from post is in
backpages
, image from comment is not.When using slots, it's just that each consecutive page can have a slot, then they load into the next in the slot hierachy rather than in layers.
sveltekit:in
, not justbackpage
- not only keeping that background already loaded, but also loading the urls, and changing the background page to another at the same time.E.g., being at
"/about"
, the code<a href="/profile/image2" sveltekit:in="/profile">link</a>
opens"/profile/image2"
as modal with"/profile"
in the background."/page/subpage1"
add a code like this:<script context="module">export const initialBackpage = "/page"; </script>
, so that the refreshed"/page/subpage1"
page is immediately opened in the modal, and immediately has"/page"
in the background. Other than thatgoto
and anchors works normally and can close this modal etc.(name
in
,backpage
andbackpages
- temporary, something to think of)Is it comfortable and versatile?
Thanks to the use of
<slot/>
, this will come in handy not only with modal.Additional Information
Rich showed some profile on Instagran as an example in the video, I'll show on some too:
when open profile:
$page
and$backpage
is profile page (e.g. https://www.instagram.com/juliazawadzka__/)when open photo on profile(code
<a href="/p/Cb7m2wdKqrh/" sveltekit:in={$backpage.url.pathname}>link</a>
):$page
is the url of the photo(e.g. https://www.instagram.com/p/Cb7m2wdKqrh/) and$backpage
is.... still profile page (https://www.instagram.com/juliazawadzka__/)The profile page is then in the background (as Rich showed), and the photo on top (in my proposal - in a
<slot/>
or on a new layer, as the profile page has no slot).Alternatives considered
Much worse:
And the equivalent for anchor needs to be improved
sveltekit:holdcontent={callback}
- changes the url a address bar likepushState
, and callback is the code right after, but does not remove the contents of"/page"
:For that, self-loading the subpage via
<svelte:component this="Subpage1Content" />
in"/page"
and self-remembering thebackpage
.Beta Was this translation helpful? Give feedback.
All reactions