Open Tobbe opened 2 years ago
Here is an example with react-router
: https://v5.reactrouter.com/web/example/modal-gallery
An important thing to consider is that the Modals should not simply wrap the Page elements. Rather, they can render anything for the same route, including Sets / Alternate Pages.
Trello is another great example
I've been thinking more about a potential future "mobile" side in Redwood. And with that I think modal based routing is going to be a more requested feature. So definitely still interested in adding support for this. But also still don't know how to do it.
An important thing to consider is that the Modals should not simply wrap the Page elements. Rather, they can render anything for the same route, including Sets / Alternate Pages.
<Set>
s are going to be interesting. A common use case for sets is to render a layout, often with a navigation bar to the left or at the top. And normally when we render a page we also render any layout(s) wrapping that page. Now, if a page is rendered inside a modal, how do we handle the sets? We have the base page that is already rendered together with its set(s). When I render this new page in a modal, should I replace the base page set? Render both sets at the base page level? Render the new set inside the modal? Not render the set at all? I don't know the answer to this question right now. Keen to hear what the rest of you think 🙂
If we consider a very simple example of a website with a gallery of images, and if you click one a modal which can navigate between images:
We'd want 2 Sets
: one for the main website, and one for the modal navigation/other elements.
And, the URL being changed with every prev/next of the image, and if we go directly to the changed url, it would show the full image without the modal/prev/next arrows, for example.
Here's a very rough idea of what the end-user code could look like:
// Routes.tsx
const ImageModalRouter = () => (
<Router>
<Set wrap={[ImageModalLayout]}> {/* ModalLayout can inspect current route and do stuff with it */}
<ImageView path="/images/{id:Int}" component={ImageComponent} />
</Set>
</Router>
)
const Routes = () => (
<Router>
<Set wrap={SiteLayout}>
<Route path="/" page={HomePage} />
<Route path="/recent" page={RecentImagesPage} modals={[ImageModalRouter]}/>
<Route path="/profile/{id:Int}" page={ProfileImagesPage} modals={[ImageModalRouter]} />
<ImageDetail path="/images/{id:Int}" page={ImagePage} /> {/* image detail page */}
</Set>
</Router>
)
React-Navigation is also worth looking into: https://reactnavigation.org/docs/nesting-navigators
@sgup Thanks for the sketches and code samples. That makes this easier to talk about 🙂
We've worked really hard to keep the routes file as flat and simple as possible. With just a single
If at all possible we'd really like to keep it that way even when adding this feature.
Another thing I'd like to think about now is animation support. Currently with our router it's very difficult (impossible?) to animate route transitions. That's something I want to change.
Right now the router can only ever render a single Page at a time. To be able to do animations and also to be able to do modal based routing we might have to change that so that two pages can be rendered simultaneously
@sgup Thanks for the sketches and code samples. That makes this easier to talk about 🙂
of course! I need my visual aids haha.
We've worked really hard to keep the routes file as flat and simple as possible. With just a single in a single file and no nesting of routes.
If at all possible we'd really like to keep it that way even when adding this feature.
Then perhaps a way to define with modal routes/sets, and simply being able to call upon them from any page:
// Routes.tsx
const Routes = () => (
<Router>
<Set wrap={SiteLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/recent" page={RecentImagesPage} name="recentImages" />
<Route path="/profile/{id:Int}" page={ProfileImagesPage} name="profileImages" />
<ImageDetail path="/images/{id:Int}" page={ImagePage} name="imageDetail" /> {/* image detail page */}
</Set>
<Modal name="imageModal">
<Set wrap={[ImageModalLayout]}> {/* ModalLayout can inspect current route and do stuff with it */}
<ImageView path="/images/{id:Int}" component={ImageComponent} name="imageView" />
</Set>
</Modal>
</Router>
)
// RecentImagesPage.tsx
() => {
const { openModal } = useNavigation()
return (
<div className="grid">
{images.map(i => <img src={i.src} onClick={openModal(routes.imageView({ id: i.id }))} />)}
</div>
)
}
Another thing I'd like to think about now is animation support. Currently with our router it's very difficult (impossible?) to animate route transitions. That's something I want to change.
I would love that! I was actually trying to animate my modal sub-views (in my hacked together modal routing solution) to be able to slide between each other. I think it would make the most sense as an animate option:
navigate(routes.home(), { ..., animation: AnimationOptions })
And actually thinking about NavigateOptions
.. maybe the modal stuff can be in that too:
navigate(routes.imageView({id: 1}), { asModal: true, ... } )
And actually thinking about
NavigateOptions
.. maybe the modal stuff can be in that too:navigate(routes.imageView({id: 1}), { asModal: true, ... } )
Yeah! That's not a bad idea.
Another option is to introduce a new <ModalRoute>
<const Routes = () => (
<Router>
<Set wrap={SiteLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/recent" page={RecentImagesPage} name="recentImages" />
<Route path="/profile/{id:Int}" page={ProfileImagesPage} name="profileImages" />
<Set wrap={ImageModalLayout}>
<ModalRoute path="/images/{id:Int}" page={ImagePage} name="imageDetail" />
</Set>
</Set>
)
And whenever you navigate to a <ModalRoute>
using navigate()
or <Link>
it'd open in a modal, but if you typed in the full url or had a bookmark or something it'd just show that as a full page
My main concern is that we're building something too specific here. If we could make something more generic, that could solve/support this use case but also other use cases people might have in the future that'd feel better. But I guess that also depends on how big this change is in the code. If the code that's unique to this feature is relatively small and self contained it's not so bad. If it makes the entire router code base even more difficult to understand that's not so great 😅
I would love that! I was actually trying to animate my modal sub-views (in my hacked together modal routing solution) to be able to slide between each other. I think it would make the most sense as an animate option:
Great! Let's think some more about this together then 🙂
navigate(routes.home(), { ..., animation: AnimationOptions })
Like for the modal routing solution a concern here is if this is too "single minded" and/or too integrated with the framework. My first idea was to rebuild the router so a user could plug in react-transition-group or framer-motion. But thinking about it some more maybe we should have built in support for animating between routes. I know Svelte has built in support for animation, and they get a lot of love for that. Maybe animation is one of our router's USPs, just like Sets. And speaking of Sets, I think it would be cool if those could be leveraged to set up animation. Either by dedicated props for it (if we go for an integrated solution), or if you could add some kind of component to the list of wrapper components that took care of animation for you.
Either by dedicated props for it (if we go for an integrated solution), or if you could add some kind of component to the list of wrapper components that took care of animation for you.
As someone who just recently began using Redwood and loving it so far, I think this is a legitimate question to ask at this point. Personally, what I love about the router is that it's lightweight and if you organize it well, it can look bomb {/**/}, put roles in arrays/objects, etc. I don't think it should be cluttered with additional props to do this? I don't remember a lot about Context when going through the tutorial, but why not add a horizontal abstraction to the 'Layout' idea and make a generator for it as well, call it an "Animate" wherein the code is defined and imported just like a Layout. Leave it to the devs to decide what kind and how many Animate components they create. Something simple like:
<const Routes = () => (
<Router>
<Set wrap={BubblesLayout} animate={BubblyTransition}>
<Route path="/" page={HomePage} name="home" />
<Route path="/bubbles" page={BubblesPage} name="bubbles" />
</Set>
</Router>
)
Didn't mean to barge into the discussion, just got interested in the topic and I apologize if I'm shooting way past the point going on here. I wonder if this discussion also touches on something like https://reactjs.org/docs/context.html (setting UI theme globally, etc.)
Didn't mean to barge into the discussion
Not at all! I very much welcome all the input here 🙂 That animate
prop on the Set does look nice 👍 Maybe that's how we should do modal routing as well
<const Routes = () => (
<Router>
<Set wrap={SiteLayout}>
<Route path="/" page={HomePage} name="home" />
<Route path="/recent" page={RecentImagesPage} name="recentImages" />
<Route path="/profile/{id:Int}" page={ProfileImagesPage} name="profileImages" />
<Set modal wrap={ImageModalLayout} animate={SlideTransition}>
<Route path="/images/add" page={AddImagePage} name="addImage" />
<Route path="/images/{id:Int}" page={ImagePage} name="imageDetail" />
</Set>
</Set>
</Router>
)
Looks clean and it fits into the current useage of 'Set' with things such as 'private'
@Tobbe @sgup any update on this issue?
@pkaramagi It's on the Core Team's roadmap. But we're all busy with other things right now, so it'll be a few more weeks, maybe months, until we get started on it.
But we're definitely here to support and guide if someone from the community wants to start experimenting before we get to it 🙂
@Tobbe @sgup any new updates on this ??
Thanks for not giving up on us @pkaramagi 🙏 Unfortunately no progress has been made on this.
Next.js just released support for this https://nextjs.org/blog/next-13-3#parallel-routes-and-interception
Any updates on this? Here are the docs on NextJS for this: https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes#modals
It's on the public roadmap for the current Bighorn Epoch. However, it's not on the near-term schedule nor has there been any implementation design work outside this Issue: http://redwoodjs.com/roadmap
Hi guys, +1 on this issue, in particular the parallel route feature that is probably needed to enable modal based routing. Having parallel routes would make it trivial to encapsulate CRUD views within a card or a modal.
Implementing support for React server components is going to require us to do some work on the router. I'll make sure to also keep this feature request in mind to see what we can do.
I added the p3 label to this issue. It just means we won't look at this specific issue as a priority right now. But it still definitely is something our router should support in the future!
Summary
Modal based routing is when you click on a link and instead of replacing the current page with the new one it opens a modal with the new page in. And as you navigate the page inside the modal the URL updates. If you bookmark the page and come back later the page that was in a modal is now the base page.
It might sound complicated/weird, but go to some instagram account on a desktop browser and you'll see exactly what I'm talking about
Motivation
It's a common/popular UI paradigm that we might want to think about adding support for in Redwood. I already mentioned that instagram does this. Another example is https://nomadlist.com
Detailed proposal
I've never tried implementing something like this, so I'm not really sure how it would work.
I'd start by trying to find existing examples of this in React using other routers, and see if I could draw some inspiration from that.
For a little more context, see here: https://community.redwoodjs.com/t/how-to-create-modal-routing/3562
Are you interested in working on this?