Skip to content

Commit d25a8df

Browse files
ia3andyCopilot
andauthored
Editor image support (#739)
* Editor image support * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent be4da14 commit d25a8df

File tree

14 files changed

+330
-417
lines changed

14 files changed

+330
-417
lines changed

blog/content/posts/2026-02-02-set-it-in-roq-the-editor-that-change-the-game/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ date: 2026-02-02 00:00:00 +0100
77
---
88
Roq started as a solid foundation for building modern apps and static sites. But now, it’s leveling up in a big way. With the introduction of a **TipTap-powered Editor with Markdown support**, Roq is no longer just an SSG tool, it’s stepping into **CMS territory**.
99

10-
![The Editor](the-roq-editor.gif)
10+
![](the-roq-editor.gif)
1111

1212
## Why This Is a Big Deal
1313

Lines changed: 12 additions & 0 deletions
Loading

roq-editor/deployment/src/main/resources/dev-ui/components/base-editor.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export class BaseEditor extends LitElement {
123123
}
124124

125125
/** Subclasses can override to return a different preview URL if needed */
126-
_getPreviewUrl() {
126+
_getPreviewUrl = () => {
127127
return this.page?.url;
128128
}
129129

@@ -218,6 +218,7 @@ export class BaseEditor extends LitElement {
218218
.activeTab="${this._activeTab}"
219219
.showEditorTab=${this.showEditorTab}
220220
@tab-changed="${this._onTabChanged}"
221+
.previewUrl="${this._getPreviewUrl()}"
221222
></qwc-toolbar>
222223
223224
<div class="preview-container" ?hidden="${this._activeTab !== 'preview'}">
@@ -232,10 +233,18 @@ export class BaseEditor extends LitElement {
232233
}
233234

234235
/** ---- Shared tab handling (subclasses may hook into before/after) ---- */
235-
_onTabChanged(e) {
236+
async _onTabChanged(e) {
236237
const newTab = e.detail.tab;
237238
const previousTab = this._activeTab;
238239

240+
if (this._isDirty && newTab === 'preview') {
241+
const save = await showConfirm('You have unsaved changes which won\'t be visible...', { title: 'Do you want to save for the preview?', cancelText: 'No thanks', confirmText: 'Save Changes' });
242+
if (save) {
243+
this._save();
244+
return;
245+
}
246+
}
247+
239248
if (this._beforeTabChange) {
240249
this._beforeTabChange(previousTab, newTab);
241250
}
@@ -265,7 +274,7 @@ export class BaseEditor extends LitElement {
265274
async _close() {
266275
if (this._isDirty) {
267276
const confirmed = await showConfirm(
268-
'Because you have unsaved changes!',
277+
'You have unsaved changes 😅',
269278
{ title: "Do you really want to close?", confirmText: 'Discard Changes', theme: 'error' }
270279
);
271280
if (!confirmed) return;

roq-editor/deployment/src/main/resources/dev-ui/components/prompt-dialog.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class PromptDialog extends LitElement {
4040
* - Without customRenderer: resolves to string or null
4141
* - With customRenderer: resolves to object or null
4242
*/
43-
prompt(message, defaultValue = '', customRenderer = null) {
43+
prompt(message, defaultValue, customRenderer = null) {
4444
return new Promise((resolve) => {
4545
this._message = message;
4646
this._defaultValue = defaultValue;
@@ -83,7 +83,12 @@ export class PromptDialog extends LitElement {
8383

8484
_handleCancel() {
8585
if (this._resolve) {
86-
this._resolve({});
86+
if(this._defaultValue && typeof this._defaultValue === 'object') {
87+
this._resolve({});
88+
} else {
89+
this._resolve(null);
90+
}
91+
8792
if (this._customRenderer) {
8893
this._formValues = JSON.parse(JSON.stringify(this._defaultFormValues));
8994
} else {
@@ -166,7 +171,7 @@ customElements.define('qwc-prompt-dialog', PromptDialog);
166171
*/
167172
let dialogInstance = null;
168173

169-
export function showPrompt(message, defaultValue = '', customRenderer = null) {
174+
export function showPrompt(message, defaultValue , customRenderer = null) {
170175
if (!dialogInstance) {
171176
dialogInstance = document.createElement('qwc-prompt-dialog');
172177
document.body.appendChild(dialogInstance);

roq-editor/deployment/src/main/resources/dev-ui/components/toolbar.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { editorContext } from './visual-editor/editor-context.js';
55
export class Toolbar extends LitElement {
66

77
static properties = {
8+
previewUrl: { type: String },
89
activeTab: { type: String, reflect: true, attribute: 'active-tab' },
910
showEditorTab: { type: Boolean }
1011
};
@@ -130,10 +131,11 @@ export class Toolbar extends LitElement {
130131
@click="${() => this._onTabClick('preview')}">
131132
Preview
132133
</button>
133-
134-
<vaadin-button theme="icon" @click="${() => this._onTabClick('previewNewTab')}">
135-
<vaadin-icon icon="font-awesome-solid:arrow-up-right-from-square"></vaadin-icon>
136-
</vaadin-button>
134+
<a href="${this.previewUrl}" target="_blank" rel="noopener noreferrer">
135+
<vaadin-button theme="icon">
136+
<vaadin-icon icon="font-awesome-solid:arrow-up-right-from-square"></vaadin-icon>
137+
</vaadin-button>
138+
</a>
137139
<div class="spacer"></div>
138140
${this.activeTab === "preview" ? html`
139141
<vaadin-button

0 commit comments

Comments
 (0)