Skip to content

Commit 568e48f

Browse files
popover
1 parent 9b2a4fd commit 568e48f

File tree

10 files changed

+218
-102
lines changed

10 files changed

+218
-102
lines changed

dist/css/field.css

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/js/field.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/components/FormField.vue

+13-11
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
'-mx-8 -mt-6' : currentField.enablePreview && !fullScreen,
1515
'fixed inset-0 bg-gray-50 z-50 flex flex-col' : fullScreen
1616
17-
}">
17+
}" style="padding-bottom: 12rem">
1818
<div v-if="fullScreen" class="px-4 py-2 z-20 bg-white border-b text-center">
1919
<button class="shadow relative bg-primary-500 hover:bg-primary-400 text-white dark:text-gray-900 cursor-pointer rounded text-sm font-bold focus:outline-none focus:ring ring-primary-200 dark:ring-gray-600 inline-flex items-center justify-center h-9 px-3" @click="selectGroup(null)">Exit full screen mode</button>
2020
</div>
@@ -137,6 +137,17 @@ export default {
137137
138138
methods: {
139139
140+
array_move(arr, old_index, new_index) {
141+
if (new_index >= arr.length) {
142+
var k = new_index - arr.length + 1;
143+
while (k--) {
144+
arr.push(undefined);
145+
}
146+
}
147+
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
148+
return arr; // for testing
149+
},
150+
140151
/**
141152
* Select the current group
142153
*/
@@ -335,16 +346,7 @@ export default {
335346
scrollSpeed: 5,
336347
animation: 500,
337348
onEnd: (evt) => {
338-
const item = evt.item;
339-
const key = item.id;
340-
const oldIndex = evt.oldIndex;
341-
const newIndex = evt.newIndex;
342-
343-
if (newIndex < oldIndex) {
344-
this.moveUp(key);
345-
} else if (newIndex > oldIndex) {
346-
this.moveDown(key);
347-
}
349+
this.order = this.array_move(this.order, evt.oldIndex, evt.newIndex);
348350
}
349351
});
350352
},

resources/js/components/FormGroup.vue

+93-59
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,28 @@
22
<div class="relative mb-4 pb-1" :id="group.key">
33
<div class="w-full shrink">
44
<div :class="titleStyle" v-if="group.title">
5-
<div class="h-8 leading-normal h-full flex items-center box-content"
5+
<div class="h-8 leading-normal flex items-center box-content"
66
:class="{'border-b border-gray-200 dark:border-gray-700 ': !collapsed}">
7-
<button
8-
dusk="expand-group"
9-
type="button"
10-
class="shrink-0 group-control btn border-r border-gray-200 dark:border-gray-700 w-8 h-8 block"
11-
:title="__('Expand')"
12-
@click.prevent="expand"
13-
v-if="collapsed">
14-
<icon type="plus" class="align-top" width="16" height="16" />
15-
</button>
16-
<button
17-
dusk="collapse-group"
18-
type="button"
19-
class="group-control btn border-r border-gray-200 dark:border-gray-700 w-8 h-8 block"
20-
:title="__('Collapse')"
21-
@click.prevent="collapse"
22-
v-else>
23-
<icon type="minus" class="align-top" width="16" height="16" />
24-
</button>
25-
26-
<p class="text-80 grow px-4">
27-
<span class="mr-3 font-semibold">#{{ index + 1 }}</span>
28-
{{ group.title }}
29-
</p>
30-
31-
<div class="flex" v-if="!readonly">
32-
<button
7+
<button
338
dusk="drag-group"
349
type="button"
3510
class="group-control btn border-l border-gray-200 dark:border-gray-700 w-8 h-8 block nova-flexible-content-drag-button"
3611
:title="__('Drag')"
3712
>
38-
<icon type="selector" class="align-top" width="16" height="16" />
39-
</button>
40-
<button
41-
dusk="move-up-group"
42-
type="button"
43-
class="group-control btn border-l border-gray-200 dark:border-gray-700 w-8 h-8 block"
44-
:title="__('Move up')"
45-
@click.prevent="moveUp">
46-
<icon type="arrow-up" class="align-top" width="16" height="16" />
47-
</button>
48-
<button
49-
dusk="move-down-group"
50-
type="button"
51-
class="group-control btn border-l border-gray-200 dark:border-gray-700 w-8 h-8 block"
52-
:title="__('Move down')"
53-
@click.prevent="moveDown">
54-
<icon type="arrow-down" class="align-top" width="16" height="16" />
13+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-4 w-4 mx-2">
14+
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 9h16.5m-16.5 6.75h16.5" />
15+
</svg>
16+
5517
</button>
18+
19+
<button @click.prevent="collapsed? expand() : collapse()" class="text-left text-80 grow">
20+
<span class="mr-3 font-semibold">#{{ index + 1 }}</span>
21+
{{ group.title }}<span v-if="collapsedPreview">: <span class="mr-3 font-semibold">{{ truncate(collapsedPreview, 30) }}</span></span>
22+
</button>
23+
24+
<div class="flex" v-if="!readonly">
25+
26+
5627
<button
5728
dusk="delete-group"
5829
type="button"
@@ -73,21 +44,49 @@
7344

7445
</div>
7546
</div>
76-
<div :class="containerStyle">
77-
<component
78-
v-for="(item, index) in group.fields"
79-
:key="index"
80-
:is="'form-' + item.component"
81-
:resource-name="resourceName"
82-
:resource-id="resourceId"
83-
:field="item"
84-
:errors="errors"
85-
:mode="mode"
86-
:show-help-text="item.helpText != null"
87-
:class="{ 'remove-bottom-border': index == group.fields.length - 1 }"
88-
/>
89-
</div>
90-
</div>
47+
48+
<transition v-if="field.drawer"
49+
enter-active-class="transition duration-200 ease-out"
50+
enter-from-class="opacity-0"
51+
enter-to-class="opacity-100"
52+
leave-active-class="transition duration-200 ease-in"
53+
leave-from-class="opacity-100"
54+
leave-to-class="opacity-0"
55+
>
56+
<div v-show="!collapsed"
57+
@click="collapse"
58+
class="fixed z-20 inset-0 bg-gray-600/75 dark:bg-gray-900/75"
59+
></div>
60+
61+
</transition>
62+
63+
<div
64+
:class="{
65+
'translate-x-full opacity-0': collapsed && field.drawer,
66+
'fixed flex flex-col z-20 top-0 transition duration-200 ease-in right-0 h-screen divide-y divide-gray-200 dark:divide-gray-700 shadow bg-white dark:bg-gray-800 w-screen max-w-4xl ml-auto border-b border-gray-200 dark:border-gray-700 overflow-x-hidden overflow-y-scroll' : field.drawer,
67+
'grow border-b border-r border-l border-gray-200 dark:border-gray-700 rounded-b-lg' : !field.drawer,
68+
'hidden': collapsed && !field.drawer }"
69+
70+
>
71+
<div v-if="field.drawer" class="-mb-px border-b border-gray-200 z-20 bg-primary-50 sticky top-0 py-5 px-6 md:px-8 flex justify-between">Edit {{ group.title }} <button class="ml-auto inline-block" @click.prevent="collapse">CLOSE</button></div>
72+
<component
73+
v-for="(item, index) in group.fields"
74+
:key="index"
75+
:is="'form-' + item.component"
76+
:resource-name="resourceName"
77+
:resource-id="resourceId"
78+
:field="item"
79+
:errors="errors"
80+
:mode="mode"
81+
:show-help-text="item.helpText != null"
82+
@change="handleFieldChanged($event, item)"
83+
:class="{ 'remove-bottom-border': index == group.fields.length - 1 }"
84+
/>
85+
</div>
86+
87+
88+
<!-- </transition> -->
89+
</div>
9190
</div>
9291
</template>
9392

@@ -113,10 +112,14 @@ export default {
113112
removeMessage: false,
114113
collapsed: this.group.collapsed,
115114
readonly: this.group.readonly,
115+
collapsedPreview: null,
116116
};
117117
},
118118
119119
computed: {
120+
collapsedPreviewAttribute() {
121+
return this.field.layouts.find(layout => layout.name === this.group.name)?.collapsedPreviewAttribute;
122+
},
120123
titleStyle() {
121124
let classes = ['border-t', 'border-r', 'border-l', 'border-gray-200', 'dark:border-gray-700', 'rounded-t-lg'];
122125
@@ -142,6 +145,19 @@ export default {
142145
}
143146
},
144147
148+
mounted() {
149+
// Object.values(this.group.fields).forEach(field => {
150+
// if (this.collapsedPreviewAttribute && this.getFieldAttribute(field) === this.collapsedPreviewAttribute) {
151+
// this.collapsedPreview = field.value;
152+
// }
153+
// });
154+
155+
this.collapsedPreview = Object.values(this.group.fields).find(field => {
156+
return this.getFieldAttribute(field) === this.collapsedPreviewAttribute;
157+
})?.value;
158+
159+
},
160+
145161
methods: {
146162
/**
147163
* Move this group up
@@ -150,6 +166,24 @@ export default {
150166
this.$emit('move-up');
151167
},
152168
169+
getFieldAttribute(item) {
170+
return item.attribute.split('__').pop();
171+
},
172+
173+
truncate(value, length) {
174+
if (value.length > length) {
175+
return value.substring(0, length) + "...";
176+
} else {
177+
return value;
178+
}
179+
},
180+
181+
handleFieldChanged(event, item) {
182+
if (this.getFieldAttribute(item) === this.collapsedPreviewAttribute) {
183+
this.collapsedPreview = event.target.value;
184+
}
185+
},
186+
153187
/**
154188
* Move this group down
155189
*/

resources/js/components/PreviewIframe.vue

+29
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,41 @@
1616
<base target='_blank' />
1717
<link rel='stylesheet' href='${stylesheet}' />
1818
<script type='module'>
19+
20+
function findVhElements() {
21+
const stylesheets = Array.from(document.styleSheets);
22+
const hasVh = str => str && str.includes('vh');
23+
return stylesheets.reduce((acc, sheet) => {
24+
const targetRules = Array.from(sheet.cssRules).filter(({ style }) =>
25+
style && ((hasVh(style.minHeight) && parseInt(style.minHeight) > 100) || (hasVh(style.height) && parseInt(style.height) > 100))
26+
);
27+
if (!targetRules.length) return acc;
28+
return acc.concat(
29+
targetRules.map(({ selectorText, style }) => {
30+
31+
return { selector: selectorText, height: style.height, minHeight: style.minHeight };
32+
33+
}).filter(el => el));
34+
}, []);
35+
}
36+
37+
function resizeVhElements() {
38+
findVhElements().forEach((item) => {
39+
console.log('resizing all: ' + item.selector);
40+
document.querySelectorAll(item.selector).forEach(
41+
(elem) => elem.style.height = parseInt(item.height) / 100 * document.body.clientHeight + 'px'
42+
);
43+
});
44+
}
45+
1946
window.addEventListener('message', (event) => {
2047
document.body.innerHTML = event.data;
2148
window.parent.postMessage('${flexible_key}', '*');
49+
resizeVhElements();
2250
});
2351
window.addEventListener('load', (event)=> {
2452
window.parent.postMessage('${flexible_key}', '*');
53+
resizeVhElements();
2554
});
2655
window.addEventListener('resize', (event)=> {
2756
window.parent.postMessage('${flexible_key}', '*');

resources/sass/field.scss

+21
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,24 @@ $multiselect-placeholder-color: #7c858e;
2222
.dark .nova-flexible-content-sortable-drag {
2323
background-color: rgba(var(--colors-gray-900),var(--tw-bg-opacity));
2424
}
25+
26+
27+
.sticky {
28+
position: sticky;
29+
}
30+
31+
.top-0 {
32+
top: 0;
33+
}
34+
35+
.translate-x-full {
36+
transform: translateX(100%);
37+
}
38+
39+
.translate-x-0 {
40+
transform: translateX(0);
41+
}
42+
43+
.-mb-px {
44+
margin-bottom: -1px;
45+
}

src/Flexible.php

+22-8
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,15 @@ public function confirmRemove($label = '', $yes = 'Delete', $no = 'Cancel')
154154
* @param string $stylesheetPath
155155
* @return $this
156156
*/
157-
public function enablePreview($stylesheetPath) {
157+
public function enablePreview($stylesheetPath)
158+
{
158159
return $this->withMeta([
159160
'enablePreview' => $stylesheetPath
160161
]);
161162
}
162163

163-
public function defaultLayouts($layouts) {
164+
public function defaultLayouts($layouts)
165+
{
164166
return $this->withMeta([
165167
'defaultLayouts' => $layouts
166168
]);
@@ -179,7 +181,7 @@ public function resolver($resolver)
179181
}
180182

181183
if (! ($resolver instanceof ResolverInterface)) {
182-
throw new \Exception('Resolver Class "'.get_class($resolver).'" does not implement ResolverInterface.');
184+
throw new \Exception('Resolver Class "' . get_class($resolver) . '" does not implement ResolverInterface.');
183185
}
184186

185187
$this->resolver = $resolver;
@@ -210,7 +212,7 @@ public function addLayout(...$arguments)
210212
}
211213

212214
if (! ($layout instanceof LayoutInterface)) {
213-
throw new \Exception('Layout Class "'.get_class($layout).'" does not implement LayoutInterface.');
215+
throw new \Exception('Layout Class "' . get_class($layout) . '" does not implement LayoutInterface.');
214216
}
215217

216218
$this->registerLayout($layout);
@@ -245,6 +247,16 @@ public function collapsed(bool $value = true)
245247
return $this;
246248
}
247249

250+
public function drawer(bool $value = true)
251+
{
252+
$this->withMeta([
253+
'collapsed' => $value,
254+
'drawer' => $value
255+
]);
256+
257+
return $this;
258+
}
259+
248260
/**
249261
* Push a layout instance into the layouts collection
250262
*
@@ -270,6 +282,7 @@ protected function registerLayout(LayoutInterface $layout)
270282
*/
271283
public function resolve($resource, $attribute = null)
272284
{
285+
273286
$attribute = $attribute ?? $this->attribute;
274287

275288
$this->registerOriginModel($resource);
@@ -594,10 +607,10 @@ protected function generateRules(NovaRequest $request, $value, $specificty)
594607

595608
$scope = ScopedRequest::scopeFrom($request, $item['attributes'], $item['key']);
596609

597-
return $group->generateRules($scope, $specificty, $this->attribute.'.'.$key);
610+
return $group->generateRules($scope, $specificty, $this->attribute . '.' . $key);
598611
})
599-
->collapse()
600-
->all();
612+
->collapse()
613+
->all();
601614
}
602615

603616
/**
@@ -627,7 +640,8 @@ protected static function registerValidationKeys(array $rules)
627640
}, $rules);
628641

629642
static::$validatedKeys = array_merge(
630-
static::$validatedKeys, $validatedKeys
643+
static::$validatedKeys,
644+
$validatedKeys
631645
);
632646
}
633647

0 commit comments

Comments
 (0)