Skip to content

Add Visual Editing to Live Preview pane#26264

Closed
bryantgillespie wants to merge 3 commits intofeat/aifrom
bry/visual-editing-preview
Closed

Add Visual Editing to Live Preview pane#26264
bryantgillespie wants to merge 3 commits intofeat/aifrom
bry/visual-editing-preview

Conversation

@bryantgillespie
Copy link
Member

@bryantgillespie bryantgillespie commented Nov 26, 2025

visual-editing-preview-pane.mp4

Adds visual editing capability to the live preview pane. This is a nice improvement for content editors where visual editing is enabled because it uses the live preview URLs to render the visual editor on the same page without having to navigate to the module. No context switching.


This pull request introduces a robust visual editing integration for live previews, improving the user experience for editing content in-place. The changes add a two-layer validation for visual editing (prerequisites and same-origin checks), enable toggling of a full-width preview mode, and streamline the handling of editable overlays and their state. Additionally, code organization and UX are improved for both regular and popup preview modes.

Key changes include:

Visual Editing Integration & Validation:

  • Added a new composable useVisualEditing to centralize the logic for determining if visual editing can be enabled, including checks for module activation, URL configuration, and item state (use-visual-editing.ts).
  • Updated live-preview.vue to accept new props for visual editing capability and allowed URLs, and to perform a same-origin check on the currently displayed URL before enabling editing. [1] [2] [3]
  • Integrated visual editing prerequisites and state into both the main content item view and the preview popup, ensuring consistent behavior and UI. [1] [2]

UI/UX Enhancements:

  • Added a full-width toggle button for the live preview panel, with state persisted via local storage and UI updates for split panel sizing. [1] [2] [3] [4]
  • Provided a toolbar button to toggle the visibility of editable elements in the live preview, and ensured overlay state resets on URL change or when editing is disabled. [1] [2] [3]

Communication & State Management:

  • Enabled the editing-layer.vue component to emit a saved event after a successful save, allowing parent components to refresh data as needed. [1] [2] [3] [4] [5]

Code Organization & Utilities:

  • Added a utility function normalizeUrl to standardize preview URLs and prevent errors from malformed inputs.
  • Moved the CSS rule for disabling pointer events on iframes during split panel dragging into the global styles for better maintainability. [1] [2]

These changes collectively make visual editing more robust, user-friendly, and maintainable.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds visual editing capability to the live preview pane, enabling content editors to edit directly within the preview without navigating to the visual module. The implementation includes a two-layer validation system (prerequisites and same-origin checks), a full-width toggle for the preview panel, and enhanced UX for managing editable overlays.

  • Introduced useVisualEditing composable for centralized prerequisite validation
  • Added same-origin validation in the live preview component
  • Implemented full-width toggle with persistent state via localStorage
  • Enhanced editing layer to emit save events for parent component refresh

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
app/src/views/private/components/live-preview.vue Added visual editing integration with two-layer validation, editable elements toggle button, and editing layer component
app/src/utils/normalize-url.ts New utility to normalize and validate URLs against the window location
app/src/styles/_base.scss Moved iframe pointer-events CSS rule to global scope for better maintainability
app/src/modules/visual/components/editing-layer.vue Added saved event emission to notify parent components of save actions
app/src/modules/content/routes/preview.vue Integrated visual editing prerequisites and configuration for popup preview mode
app/src/modules/content/routes/item.vue Added full-width toggle, visual editing integration, and save event handler for the split panel preview
app/src/composables/use-visual-editing.ts New composable for checking visual editing prerequisites including module status, URL configuration, and item state

Comment on lines +1 to +13
/**
* Normalizes a URL string by resolving it against the current window location.
* Returns null if the URL is invalid or empty.
*/
export function normalizeUrl(url: string | null): string | null {
if (!url) return null;

try {
return new URL(url, window.location.href).href;
} catch {
return null;
}
}
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the normalizeUrl utility function. Since the app/src/utils directory contains comprehensive test files for most utility functions (e.g., add-query-to-path.test.ts, format-filesize.test.ts), this new utility should also have test coverage to ensure it correctly handles edge cases like:

  • Invalid URLs
  • Relative URLs
  • Absolute URLs
  • Empty/null inputs
  • URLs with special characters

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +44
import { computed, unref, type MaybeRef } from 'vue';
import { MODULE_BAR_DEFAULT } from '@/constants';
import { useSettingsStore } from '@/stores/settings';
import { normalizeUrl } from '@/utils/normalize-url';

interface UseVisualEditingOptions {
/** Preview URL to check (will be normalized internally) */
previewUrl: MaybeRef<string | null>;
/** Whether this is a new item - visual editing is disabled for new items. Defaults to false. */
isNew?: MaybeRef<boolean>;
}

/**
* Handles visual editing prerequisites check.
* Returns whether visual editing can be enabled and the allowed URLs for sameOrigin validation.
*
* Note: This checks prerequisites only. The live-preview component does the final
* sameOrigin validation against the currently displayed URL.
*/
export function useVisualEditing({ previewUrl, isNew = false }: UseVisualEditingOptions) {
const settingsStore = useSettingsStore();
const moduleBar = computed(() => settingsStore.settings?.module_bar ?? MODULE_BAR_DEFAULT);

const visualEditorUrls = computed(
() => settingsStore.settings?.visual_editor_urls?.map(({ url }) => url).filter(Boolean) ?? [],
);

const visualModuleEnabled = computed(() =>
moduleBar.value.some((part) => part.type === 'module' && part.id === 'visual' && part.enabled),
);

const normalizedPreviewUrl = computed(() => normalizeUrl(unref(previewUrl)));

/** Prerequisites check - live-preview does the final sameOrigin validation */
const visualEditingEnabled = computed(
() =>
!!normalizedPreviewUrl.value &&
!unref(isNew) &&
visualModuleEnabled.value &&
visualEditorUrls.value.length > 0,
);

return { visualEditingEnabled, visualEditorUrls };
}
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the useVisualEditing composable. Since the app/src/composables directory contains comprehensive test files for composables (e.g., use-event-listener.test.ts, use-local-storage.test.ts), this new composable should have test coverage to verify:

  • Correct handling of prerequisites (module enabled, URLs configured, valid item state)
  • Behavior with new vs. existing items
  • URL normalization integration
  • Reactive updates when dependencies change

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +108
* Two-layer visual editing check:
* 1. Parent checks prerequisites (module enabled, URLs configured, valid item state)
* 2. Child checks if the *currently displayed* URL (frameSrc) passes sameOrigin
*
* We use frameSrc here because the user may have selected a different URL from the dropdown
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment describes a "two-layer visual editing check" but the logic only performs a single-layer check at this location. The parent's prerequisite check happens in useVisualEditing, but this comment implies both checks happen here. Consider clarifying the comment to reflect that this is performing the second layer (sameOrigin validation) based on the first layer's result passed via the canEnableVisualEditing prop.

Suggested change
* Two-layer visual editing check:
* 1. Parent checks prerequisites (module enabled, URLs configured, valid item state)
* 2. Child checks if the *currently displayed* URL (frameSrc) passes sameOrigin
*
* We use frameSrc here because the user may have selected a different URL from the dropdown
* Visual editing enablement (second-layer check):
* This computed property only performs the second layer of the visual editing check:
* - It checks if the *currently displayed* URL (frameSrc) passes sameOrigin validation
* The first layer (prerequisite check: module enabled, URLs configured, valid item state)
* is handled by the parent and passed via the `canEnableVisualEditing` prop.
* We use frameSrc here because the user may have selected a different URL from the dropdown.

Copilot uses AI. Check for mistakes.
@bryantgillespie bryantgillespie changed the title AI / Split Panel -> Add Visual Editing to Live Preview pane Add Visual Editing to Live Preview pane Nov 26, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants