Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions config/areas/site/buttons.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
'site.preview' => function (Site $site) {
if ($site->previewUrl() !== null) {
return new PreviewButton(
link: $site->panel()->url(true) . '/preview/changes',
link: $site->panel()->url(true) . '/preview/form',
);
}
},
'site.versions' => fn (Site $site, string $mode = 'latest') => new VersionsButton(
'site.versions' => fn (Site $site, string $mode = 'form') => new VersionsButton(
model: $site,
mode: $mode
),
Expand All @@ -33,11 +33,11 @@
'page.preview' => function (Page $page) {
if ($page->previewUrl() !== null) {
return new PreviewButton(
link: $page->panel()->url(true) . '/preview/changes',
link: $page->panel()->url(true) . '/preview/form',
);
}
},
'page.versions' => fn (Page $page, string $mode = 'latest') => new VersionsButton(
'page.versions' => fn (Page $page, string $mode = 'form') => new VersionsButton(
model: $page,
mode: $mode
),
Expand Down
20 changes: 14 additions & 6 deletions config/areas/site/views.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?php

use Kirby\Panel\Controller\View\PageFileViewController;
use Kirby\Panel\Controller\View\PagePreviewViewController;
use Kirby\Panel\Controller\View\PageViewController;
use Kirby\Panel\Controller\View\PreviewViewController;
use Kirby\Panel\Controller\View\RemotePreviewViewController;
use Kirby\Panel\Controller\View\SiteFileViewController;
use Kirby\Panel\Controller\View\SitePreviewViewController;
use Kirby\Panel\Controller\View\SiteViewController;

return [
Expand All @@ -17,8 +17,12 @@
'action' => PageFileViewController::class
],
'page.preview' => [
'pattern' => '(pages/.*?)/preview/(changes|latest|compare)',
'action' => PagePreviewViewController::class
'pattern' => '(pages/.*?)/preview/(changes|latest|compare|form)',
'action' => PreviewViewController::class
],
'page.preview.remote' => [
'pattern' => '(pages/.*?)/preview/(form)/remote',
'action' => RemotePreviewViewController::class
],
'site' => [
'pattern' => 'site',
Expand All @@ -29,7 +33,11 @@
'action' => SiteFileViewController::class
],
'site.preview' => [
'pattern' => '(site)/preview/(changes|latest|compare)',
'action' => SitePreviewViewController::class
'pattern' => '(site)/preview/(changes|latest|compare|form)',
'action' => PreviewViewController::class
],
'site.preview.remote' => [
'pattern' => '(site)/preview/(form)/remote',
'action' => RemotePreviewViewController::class
],
];
4 changes: 4 additions & 0 deletions i18n/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,10 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Previous",

"preview": "Preview",
"preview.browser.pin": "Toggle whether preview navigation should be in sync or independent",
"preview.browser.scroll": "Sync scroll",

"publish": "Publish",
"published": "Published",
Expand Down Expand Up @@ -788,6 +791,7 @@
"version.changes": "Changed version",
"version.compare": "Compare versions",
"version.current": "Current version",
"version.form": "Live editor",
"version.latest": "Latest version",
"versionInformation": "Version information",

Expand Down
9 changes: 9 additions & 0 deletions panel/public/img/icons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion panel/src/components/Drawers/Elements/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ export default {
margin-block: 0;
}
.k-drawer-tabs .k-tabs-button[aria-current="true"]::after {
z-index: 1;
z-index: var(--z-toolbar);
Comment thread
bastianallgeier marked this conversation as resolved.
}
</style>
1 change: 0 additions & 1 deletion panel/src/components/Layout/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ export default {
text: tab.label ?? tab.text ?? tab.name
};


if (typeof tab.badge === "string") {
button.badge = {
text: tab.badge
Expand Down
2 changes: 1 addition & 1 deletion panel/src/components/Navigation/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export default {
display: inline-flex;
align-items: center;
justify-content: var(--button-align);
gap: 0.5rem;
gap: var(--spacing-2);
padding-inline: var(--button-padding);
white-space: nowrap;
line-height: 1;
Expand Down
7 changes: 5 additions & 2 deletions panel/src/components/Navigation/ModelTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
*/
export default {
props: {
diff: Object,
diff: {
type: Object,
default: () => ({})
},
tab: String,
tabs: {
type: Array,
Expand Down Expand Up @@ -41,7 +44,7 @@ export default {

return {
...tab,
badge: changesInTab > 0 ? { text: changesInTab } : null
badge: changesInTab > 0 ? { text: changesInTab } : undefined
};
});
}
Expand Down
2 changes: 2 additions & 0 deletions panel/src/components/Sections/FieldsSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export default {
this.issue = error;
} finally {
this.isLoading = false;
await this.$nextTick();
this.$events.emit("section.loaded", this);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions panel/src/components/Sections/ModelsSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ export default {
} finally {
this.isProcessing = false;
this.isLoading = false;

await this.$nextTick();
this.$events.emit("section.loaded", this);
}
},
onAction() {},
Expand Down
1 change: 1 addition & 0 deletions panel/src/components/Sections/Sections.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
:text="empty"
theme="info"
/>

<k-grid v-else class="k-sections" variant="columns">
<k-column
v-for="(column, columnIndex) in tab.columns"
Expand Down
158 changes: 127 additions & 31 deletions panel/src/components/Views/Preview/PreviewBrowser.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<template>
<div class="k-preview-browser">
<header class="k-preview-browser-header">
<k-headline>
<header v-if="label" class="k-preview-browser-header">
<k-headline class="k-preview-headline">
<k-icon type="git-branch" />
{{ label }}
</k-headline>

<k-button-group>
<template v-if="mode === 'changes'">
<p v-if="hasDiff === false" class="k-preview-browser-message">
Expand All @@ -15,18 +16,37 @@
:editor="editor"
:has-diff="hasDiff"
:is-locked="isLocked"
:is-processing="isSaving"
:is-processing="isProcessing"
:modified="modified"
size="xs"
@discard="$emit('discard', $event)"
@submit="$emit('submit', $event)"
/>
</template>
<k-button :link="src" icon="open" size="xs" target="_blank" />

<k-button
v-if="mode === 'form'"
:aria-checked="isPinned"
:title="$t('preview.browser.pin')"
:theme="isPinned ? 'info' : 'passive'"
:variant="isPinned ? 'filled' : 'none'"
icon="pushpin"
role="switch"
size="sm"
@click="$emit('pin')"
/>
<k-button
v-if="open"
:link="open"
icon="open"
size="xs"
target="_blank"
@click="$emit('open')"
/>
</k-button-group>
</header>

<iframe ref="browser" :src="srcWithPreviewParam" />
<iframe ref="browser" :src="src" @load="onLoad" />
</div>
</template>

Expand All @@ -36,29 +56,115 @@ import { props } from "@/components/Forms/FormControls.vue";
export default {
mixins: [props],
props: {
isPinned: Boolean,
label: String,
src: String,
mode: String
mode: String,
open: String
},
emits: ["discard", "submit"],
emits: ["discard", "navigate", "open", "pin", "scroll", "submit"],
computed: {
srcWithPreviewParam() {
const uri = new URL(this.src, this.$panel.urls.site);
uri.searchParams.append("_preview", true);
return uri.toString();
window() {
return this.$refs.browser.contentWindow;
}
},
mounted() {
this.$events.on("content.discard", this.reload);
this.$events.on("content.publish", this.reload);
},
unmounted() {
this.$events.off("content.discard", this.reload);
this.$events.off("content.publish", this.reload);
},
methods: {
/**
* Handle link clicks inside the iframe
*/
onClick(e) {
const link = e.target.closest("a");

if (!link) {
return;
}

if (!link.href || link.onclick) {
return;
}

// open external links and Panel links in new tab
if (
link.href.startsWith(location.origin) === false ||
link.href.startsWith(this.$panel.urls.panel) === true
) {
link.target = "_blank";
return true;
}

// catch internal links and emit navigate event
e.preventDefault(e);

if (this.isPinned) {
// we only want to refresh the browser for the target
this.$emit("navigate", { browser: link.href });
} else {
// we want to refresh the whole view for the target
this.$emit("navigate", { view: link.href });
}
},
onLoad() {
const document = this.$refs.browser.contentDocument;

// if the browser got redirected during load
// navigate to the proper preview URL for this new URL
// (but only if the new URL doesn't already contain _version and _token)
if (this.src !== document.URL) {
const url = new URL(document.URL);

if (
url.searchParams.has("_token") === false ||
url.searchParams.has("_version") === false
) {
return this.$emit("navigate", { browser: url });
}
}

// attach event listeners to all links inside the iframe
document.addEventListener("click", this.onClick);

for (const link of document.querySelectorAll("a")) {
link.addEventListener("click", this.onClick);
}

document.addEventListener("scroll", (e) => this.$emit("scroll", e));
},
/**
* Refresh the iframe
* (e.g. for content updates)
*/
reload() {
this.$refs.browser.contentWindow.location.reload();
this.window.location.reload();
},
/**
* Restore an iframe URL and scroll position
* (only when iframe browser is pinned)
*/
restore({ src, scroll }) {
// if the browser isn't pinned, we keep it as loaded with the view
if (!this.isPinned) {
return;
}

// restore scroll position once the iframe finished loading
this.$refs.browser.addEventListener(
"load",
() => this.window.scrollTo(0, scroll),
{ once: true }
);

// load restored URL in iframe
this.$refs.browser.src = src;
},
/**
* Returns the current iframe URL and scroll position,
* so that these can be restored, if needed
*/
store() {
return {
src: this.$refs.browser.src,
scroll: this.window.scrollY
};
}
}
};
Expand Down Expand Up @@ -89,18 +195,8 @@ export default {
padding-inline: var(--spacing-2);
height: var(--input-height);
}
.k-preview-browser header .k-headline {
display: flex;
align-items: center;
gap: var(--spacing-1);
font-weight: var(--font-normal);
font-size: var(--text-xs);
padding-inline: var(--spacing-1);
}
.k-preview-browser-header .k-form-controls-button {
.k-preview-browser-header .k-preview-headline {
font-size: var(--text-xs);
--button-rounded: 3px;
--icon-size: 1rem;
}
.k-preview-browser-message {
font-size: var(--text-xs);
Expand Down
Loading