Skip to content

Commit 4eaba75

Browse files
committed
WIP base url
1 parent f875545 commit 4eaba75

File tree

7 files changed

+163
-14
lines changed

7 files changed

+163
-14
lines changed

demo-app/app/InertiaUIModal.php

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace App;
4+
5+
use Illuminate\Contracts\Support\Responsable;
6+
use Illuminate\Http\Request;
7+
use Illuminate\Routing\Middleware\SubstituteBindings;
8+
use Illuminate\Support\Facades\Route;
9+
10+
class InertiaUIModal implements Responsable
11+
{
12+
public function __construct(protected array $modalData)
13+
{
14+
//
15+
}
16+
17+
/**
18+
* {@inheritdoc}
19+
*
20+
* @see https://github.com/lepikhinb/momentum-modal/blob/b45992e4982859990a076dd924e19e589ff9797e/src/Modal.php
21+
*/
22+
public function toResponse($originalRequest)
23+
{
24+
inertia()->share('_inertiaui_modal', $this->modalData);
25+
26+
$requestForBaseUrl = Request::create(
27+
$this->modalData['baseUrl'],
28+
Request::METHOD_GET,
29+
$originalRequest->query->all(),
30+
$originalRequest->cookies->all(),
31+
$originalRequest->files->all(),
32+
$originalRequest->server->all(),
33+
$originalRequest->getContent()
34+
);
35+
36+
$requestForBaseUrl->headers->replace($originalRequest->headers->all());
37+
$requestForBaseUrl->setRequestLocale($originalRequest->getLocale());
38+
$requestForBaseUrl->setDefaultRequestLocale($originalRequest->getDefaultLocale());
39+
40+
if ($originalRequest->hasSession() && $session = $originalRequest->session()) {
41+
$requestForBaseUrl->setLaravelSession($session);
42+
}
43+
44+
$baseRoute = Route::getRoutes()->match($requestForBaseUrl);
45+
46+
$requestForBaseUrl
47+
->setJson($originalRequest->json())
48+
->setUserResolver(fn () => $originalRequest->getUserResolver())
49+
->setRouteResolver(fn () => $baseRoute);
50+
51+
app()->instance('request', $requestForBaseUrl);
52+
53+
return (new SubstituteBindings(Route::getFacadeRoot()))->handle(
54+
$requestForBaseUrl, fn () => $baseRoute->run()
55+
)->toResponse($originalRequest);
56+
}
57+
}

demo-app/app/Providers/AppServiceProvider.php

+14-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
namespace App\Providers;
44

5+
use App\InertiaUIModal;
56
use Illuminate\Database\Eloquent\Model;
67
use Illuminate\Support\ServiceProvider;
8+
use Inertia\Response;
79

810
class AppServiceProvider extends ServiceProvider
911
{
@@ -12,7 +14,18 @@ class AppServiceProvider extends ServiceProvider
1214
*/
1315
public function register(): void
1416
{
15-
//
17+
Response::macro('modal', function ($baseUrl) {
18+
if (request()->header('X-InertiaUI-Modal')) {
19+
return $this;
20+
}
21+
22+
return new InertiaUIModal([
23+
'baseUrl' => $baseUrl,
24+
'component' => $this->component,
25+
'props' => $this->props,
26+
'version' => $this->version,
27+
]);
28+
});
1629
}
1730

1831
/**

demo-app/routes/web.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
return inertia('EditUser', [
1111
'roles' => Role::pluck('name', 'id'),
1212
'user' => $user,
13-
]);
13+
])->modal(url('/users'));
1414
})->name('users.edit');
1515

1616
// Update a user

vue/.prettierrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"singleAttributePerLine": true,
55
"singleQuote": true,
66
"tabWidth": 4,
7-
"printWidth": 160,
7+
"printWidth": 150,
88
"plugins": [
99
"prettier-plugin-tailwindcss"
1010
]

vue/src/ModalLink.vue

+20-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { modalPropNames, useModalStack } from './modalStack'
33
import { ref, provide, watch, onMounted, useAttrs, onBeforeUnmount } from 'vue'
44
import { only, rejectNullValues } from './helpers'
5+
import { router } from '@inertiajs/vue3'
56
67
const props = defineProps({
78
href: {
@@ -32,6 +33,10 @@ const props = defineProps({
3233
type: String,
3334
default: 'brackets',
3435
},
36+
navigate: {
37+
type: Boolean,
38+
default: false,
39+
},
3540
// Passthrough to Modal.vue
3641
closeButton: {
3742
type: Boolean,
@@ -142,6 +147,17 @@ function handle() {
142147
if (!props.href.startsWith('#')) {
143148
loading.value = true
144149
emit('start')
150+
151+
if (props.navigate) {
152+
return router.visit(props.href, {
153+
method: props.method,
154+
data: props.data,
155+
headers: props.headers,
156+
onFinished: () => {
157+
loading.value = false
158+
},
159+
})
160+
}
145161
}
146162
147163
modalStack
@@ -155,7 +171,10 @@ function handle() {
155171
onAfterLeave,
156172
props.queryStringArrayFormat,
157173
)
158-
.then((context) => (modalContext.value = context))
174+
.then((context) => {
175+
console.log(context)
176+
modalContext.value = context
177+
})
159178
.catch((error) => emit('error', error))
160179
.finally(() => (loading.value = false))
161180
}

vue/src/ModalRoot.vue

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup>
2-
import { onBeforeMount } from 'vue'
2+
import { onBeforeMount, onUnmounted, ref } from 'vue'
3+
import { router } from '@inertiajs/vue3'
34
import { useModalStack } from './modalStack'
45
import ModalRenderer from './ModalRenderer.vue'
56
@@ -8,6 +9,31 @@ const modalStack = useModalStack()
89
onBeforeMount(() => {
910
modalStack.rootPresent.value = true
1011
})
12+
13+
const activeModalFromBaseUrl = ref(null)
14+
const isNavigating = ref(false)
15+
16+
onUnmounted(router.on('start', () => (isNavigating.value = true)))
17+
onUnmounted(router.on('finish', () => (isNavigating.value = false)))
18+
onUnmounted(
19+
router.on('navigate', (event) => {
20+
const modalOnBase = event.detail.page.props._inertiaui_modal
21+
22+
if (!modalOnBase) {
23+
activeModalFromBaseUrl.value?.close()
24+
activeModalFromBaseUrl.value = null
25+
return
26+
}
27+
28+
modalStack
29+
.pushFromResponseData(modalOnBase, {}, () => {
30+
if (!isNavigating.value && window.location.href !== modalOnBase.baseUrl) {
31+
router.visit(modalOnBase.baseUrl)
32+
}
33+
})
34+
.then((modal) => (activeModalFromBaseUrl.value = modal))
35+
}),
36+
)
1137
</script>
1238
1339
<template>

vue/src/modalStack.js

+43-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { computed, readonly, ref, markRaw } from 'vue'
1+
import { computed, readonly, ref, markRaw, nextTick } from 'vue'
22
import { default as Axios } from 'axios'
33
import { except, only } from './helpers'
44
import { router, usePage } from '@inertiajs/vue3'
@@ -10,7 +10,7 @@ const localModals = ref({})
1010
class Modal {
1111
constructor(component, response, modalProps, onClose, afterLeave) {
1212
this.id = Modal.generateId()
13-
this.open = true
13+
this.open = false
1414
this.listeners = {}
1515

1616
this.component = component
@@ -43,9 +43,28 @@ class Modal {
4343
return stack.value.length < 2 || stack.value[stack.value.length - 1].id === this.id
4444
}
4545

46+
show = () => {
47+
const index = this.index.value
48+
49+
if (index > -1) {
50+
if (stack.value[index].open) {
51+
// Only open if the modal is closed
52+
return
53+
}
54+
55+
stack.value[index].open = true
56+
}
57+
}
58+
4659
close = () => {
4760
const index = this.index.value
61+
4862
if (index > -1) {
63+
if (!stack.value[index].open) {
64+
// Only close if the modal is open
65+
return
66+
}
67+
4968
Object.keys(this.listeners).forEach((event) => {
5069
this.off(event)
5170
})
@@ -56,8 +75,17 @@ class Modal {
5675
}
5776

5877
afterLeave = () => {
59-
stack.value = stack.value.filter((m) => m.id !== this.id)
60-
this.afterLeaveCallback?.()
78+
const index = this.index.value
79+
80+
if (index > -1) {
81+
if (stack.value[index].open) {
82+
// Only execute the callback if the modal is closed
83+
return
84+
}
85+
86+
stack.value = stack.value.filter((m) => m.id !== this.id)
87+
this.afterLeaveCallback?.()
88+
}
6189
}
6290

6391
on = (event, callback) => {
@@ -137,6 +165,12 @@ function pushLocalModal(name, modalProps, onClose, afterLeave) {
137165
return modal
138166
}
139167

168+
function pushFromResponseData(responseData, modalProps = {}, onClose = null, onAfterLeave = null) {
169+
return router
170+
.resolveComponent(responseData.component)
171+
.then((component) => push(markRaw(component), responseData, modalProps, onClose, onAfterLeave))
172+
}
173+
140174
function visit(href, method, payload = {}, headers = {}, modalProps = {}, onClose = null, onAfterLeave = null, queryStringArrayFormat = 'brackets') {
141175
return new Promise((resolve, reject) => {
142176
if (href.startsWith('#')) {
@@ -159,11 +193,7 @@ function visit(href, method, payload = {}, headers = {}, modalProps = {}, onClos
159193
'X-InertiaUI-Modal': true,
160194
},
161195
})
162-
.then((response) => {
163-
router.resolveComponent(response.data.component).then((component) => {
164-
resolve(push(markRaw(component), response.data, modalProps, onClose, onAfterLeave))
165-
})
166-
})
196+
.then((response) => resolve(pushFromResponseData(response.data, modalProps, onClose, onAfterLeave)))
167197
.catch((error) => {
168198
reject(error)
169199
})
@@ -173,6 +203,9 @@ function visit(href, method, payload = {}, headers = {}, modalProps = {}, onClos
173203
function push(component, response, modalProps, onClose, afterLeave) {
174204
const newModal = new Modal(component, response, modalProps, onClose, afterLeave)
175205
stack.value.push(newModal)
206+
nextTick(() => {
207+
newModal.show()
208+
})
176209
return newModal
177210
}
178211

@@ -184,6 +217,7 @@ export function useModalStack() {
184217
return {
185218
stack: readonly(stack),
186219
push,
220+
pushFromResponseData,
187221
reset: () => (stack.value = []),
188222
visit,
189223
registerLocalModal,

0 commit comments

Comments
 (0)