Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9b47487
refactor: move loading more styles inside the _style function for con…
devvaannsh Sep 25, 2025
4cc20e4
feat: localize all the strings used in image ribbon gallery
devvaannsh Sep 25, 2025
aeb53db
fix: downloaded images are blurry compared to previewed images
devvaannsh Sep 25, 2025
e7fcb12
feat: use local storage instead of cache to reduce API calls
devvaannsh Sep 26, 2025
e25b80f
fix: live preview getting scrolled even when the element is completel…
devvaannsh Sep 26, 2025
fe6122e
fix: info box and more options box points at different elements after…
devvaannsh Sep 27, 2025
63d3ad3
refactor: remove redundant dismissed tracking
devvaannsh Sep 27, 2025
21ba7fe
fix: select parent click function throws error when element is of svg…
devvaannsh Sep 27, 2025
e161348
fix: shouldn't show edit text button for svg children elements
devvaannsh Sep 27, 2025
08f983a
refactor: improve UI to make it consistent
devvaannsh Sep 27, 2025
a29143a
refactor: use more intuitive icon for select image from computer button
devvaannsh Sep 28, 2025
a41ac65
feat: move image gallery inside more options box
devvaannsh Sep 28, 2025
0a9a27a
feat: remove show image gallery option from dropdown
devvaannsh Oct 3, 2025
f100bd7
refactor: use distinct icon for select image from computer button
devvaannsh Oct 3, 2025
71e84d4
feat: ask users to select the folder where they want to download the …
devvaannsh Oct 4, 2025
616271e
feat: show folder suggestions when typing a folder name in the dialog
devvaannsh Oct 5, 2025
c0c1fc4
feat: add keyboard navigation in the suggestions list
devvaannsh Oct 5, 2025
3a91c95
feat: improve match goodness algorithm to show more useful hints
devvaannsh Oct 6, 2025
8f577b9
feat: make the folder suggestion list scrollable
devvaannsh Oct 6, 2025
7a90189
fix: feels laggy because of transition
devvaannsh Oct 6, 2025
813acd2
feat: save folder location in state manager project wise
devvaannsh Oct 6, 2025
8dc934c
feat: add download folder button reset mechanism
devvaannsh Oct 7, 2025
a7288e8
feat: localize all strings
devvaannsh Oct 7, 2025
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
595 changes: 394 additions & 201 deletions src/LiveDevelopment/BrowserScripts/RemoteFunctions.js

Large diffs are not rendered by default.

12 changes: 1 addition & 11 deletions src/LiveDevelopment/LiveDevMultiBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -714,17 +714,8 @@ define(function (require, exports, module) {
*/
function dismissLivePreviewBoxes() {
if (_protocol) {
_protocol.evaluate("_LD.enableHoverListeners()"); // so that if hover lock is there it will get cleared
_protocol.evaluate("_LD.dismissUIAndCleanupState()");
_protocol.evaluate("_LD.dismissImageRibbonGallery()");
}
}

/**
* Dismiss image ribbon gallery if it's open
*/
function dismissImageRibbonGallery() {
if (_protocol) {
_protocol.evaluate("_LD.dismissImageRibbonGallery()");
}
}

Expand Down Expand Up @@ -814,7 +805,6 @@ define(function (require, exports, module) {
exports.redrawHighlight = redrawHighlight;
exports.hasVisibleLivePreviewBoxes = hasVisibleLivePreviewBoxes;
exports.dismissLivePreviewBoxes = dismissLivePreviewBoxes;
exports.dismissImageRibbonGallery = dismissImageRibbonGallery;
exports.registerHandlers = registerHandlers;
exports.updateConfig = updateConfig;
exports.init = init;
Expand Down
378 changes: 352 additions & 26 deletions src/LiveDevelopment/LivePreviewEdit.js

Large diffs are not rendered by default.

26 changes: 8 additions & 18 deletions src/LiveDevelopment/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ define(function main(require, exports, module) {
},
isProUser: isProUser,
elemHighlights: "hover", // default value, this will get updated when the extension loads
imageRibbon: true, // default value, this will get updated when the extension loads
// this strings are used in RemoteFunctions.js
// we need to pass this through config as remoteFunctions runs in browser context and cannot
// directly reference Strings file
Expand All @@ -80,11 +79,17 @@ define(function main(require, exports, module) {
duplicate: Strings.LIVE_DEV_MORE_OPTIONS_DUPLICATE,
delete: Strings.LIVE_DEV_MORE_OPTIONS_DELETE,
ai: Strings.LIVE_DEV_MORE_OPTIONS_AI,
imageGallery: Strings.LIVE_DEV_MORE_OPTIONS_IMAGE_GALLERY,
aiPromptPlaceholder: Strings.LIVE_DEV_AI_PROMPT_PLACEHOLDER,
imageGalleryUseImage: Strings.LIVE_DEV_IMAGE_GALLERY_USE_IMAGE,
imageGallerySelectFromComputer: Strings.LIVE_DEV_IMAGE_GALLERY_SELECT_FROM_COMPUTER,
imageGalleryChooseFolder: Strings.LIVE_DEV_IMAGE_GALLERY_CHOOSE_FOLDER,
imageGallerySearchPlaceholder: Strings.LIVE_DEV_IMAGE_GALLERY_SEARCH_PLACEHOLDER
imageGallerySelectDownloadFolder: Strings.LIVE_DEV_IMAGE_GALLERY_SELECT_DOWNLOAD_FOLDER,
imageGallerySearchPlaceholder: Strings.LIVE_DEV_IMAGE_GALLERY_SEARCH_PLACEHOLDER,
imageGallerySearchButton: Strings.LIVE_DEV_IMAGE_GALLERY_SEARCH_BUTTON,
imageGalleryLoadingInitial: Strings.LIVE_DEV_IMAGE_GALLERY_LOADING_INITIAL,
imageGalleryLoadingMore: Strings.LIVE_DEV_IMAGE_GALLERY_LOADING_MORE,
imageGalleryNoImages: Strings.LIVE_DEV_IMAGE_GALLERY_NO_IMAGES,
imageGalleryLoadError: Strings.LIVE_DEV_IMAGE_GALLERY_LOAD_ERROR
}
};
// Status labels/styles are ordered: error, not connected, progress1, progress2, connected.
Expand Down Expand Up @@ -370,20 +375,6 @@ define(function main(require, exports, module) {
}
}

// this function is responsible to update image picker config
// called from live preview extension when preference changes
function updateImageRibbonConfig() {
const prefValue = PreferencesManager.get("livePreviewImagePicker");
config.imageRibbon = prefValue !== false; // default to true if undefined

if (MultiBrowserLiveDev && MultiBrowserLiveDev.status >= MultiBrowserLiveDev.STATUS_ACTIVE) {
if (!prefValue) { MultiBrowserLiveDev.dismissImageRibbonGallery(); } // to remove any existing image ribbons

MultiBrowserLiveDev.updateConfig(JSON.stringify(config));
MultiBrowserLiveDev.registerHandlers();
}
}

// init commands
CommandManager.register(Strings.CMD_LIVE_HIGHLIGHT, Commands.FILE_LIVE_HIGHLIGHT, togglePreviewHighlight);
CommandManager.register(Strings.CMD_RELOAD_LIVE_PREVIEW, Commands.CMD_RELOAD_LIVE_PREVIEW, _handleReloadLivePreviewCommand);
Expand Down Expand Up @@ -412,7 +403,6 @@ define(function main(require, exports, module) {
exports.togglePreviewHighlight = togglePreviewHighlight;
exports.setLivePreviewEditFeaturesActive = setLivePreviewEditFeaturesActive;
exports.updateElementHighlightConfig = updateElementHighlightConfig;
exports.updateImageRibbonConfig = updateImageRibbonConfig;
exports.getConnectionIds = MultiBrowserLiveDev.getConnectionIds;
exports.getLivePreviewDetails = MultiBrowserLiveDev.getLivePreviewDetails;
exports.hideHighlight = MultiBrowserLiveDev.hideHighlight;
Expand Down
29 changes: 0 additions & 29 deletions src/extensionsIntegrated/Phoenix-live-preview/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,6 @@ define(function (require, exports, module) {
description: Strings.LIVE_DEV_SETTINGS_ELEMENT_HIGHLIGHT_PREFERENCE
});

// live preview image picker preference (whether to show image gallery when clicking images)
const PREFERENCE_PROJECT_IMAGE_RIBBON = "livePreviewImagePicker";
PreferencesManager.definePreference(PREFERENCE_PROJECT_IMAGE_RIBBON, "boolean", true, {
description: Strings.LIVE_PREVIEW_EDIT_IMAGE_RIBBON
});

const LIVE_PREVIEW_PANEL_ID = "live-preview-panel";
const LIVE_PREVIEW_IFRAME_ID = "panel-live-preview-frame";
const LIVE_PREVIEW_IFRAME_HTML = `
Expand Down Expand Up @@ -425,7 +419,6 @@ define(function (require, exports, module) {
if (isEditFeaturesActive) {
items.push("---");
items.push(Strings.LIVE_PREVIEW_EDIT_HIGHLIGHT_ON);
items.push(Strings.LIVE_PREVIEW_EDIT_IMAGE_RIBBON);
}

const rawMode = PreferencesManager.get(PREFERENCE_LIVE_PREVIEW_MODE) || _getDefaultMode();
Expand All @@ -451,12 +444,6 @@ define(function (require, exports, module) {
return `✓ ${Strings.LIVE_PREVIEW_EDIT_HIGHLIGHT_ON}`;
}
return `${'\u00A0'.repeat(4)}${Strings.LIVE_PREVIEW_EDIT_HIGHLIGHT_ON}`;
} else if (item === Strings.LIVE_PREVIEW_EDIT_IMAGE_RIBBON) {
const isImageRibbonEnabled = PreferencesManager.get(PREFERENCE_PROJECT_IMAGE_RIBBON) !== false;
if(isImageRibbonEnabled) {
return `✓ ${item}`;
}
return `${'\u00A0'.repeat(4)}${item}`;
}
return item;
});
Expand Down Expand Up @@ -505,15 +492,6 @@ define(function (require, exports, module) {
const newMode = currentMode !== "click" ? "click" : "hover";
PreferencesManager.set(PREFERENCE_PROJECT_ELEMENT_HIGHLIGHT, newMode);
return; // Don't dismiss highlights for this option
} else if (item === Strings.LIVE_PREVIEW_EDIT_IMAGE_RIBBON) {
// Don't allow image ribbon toggle if edit features are not active
if (!isEditFeaturesActive) {
return;
}
// Toggle image ribbon preference
const currentEnabled = PreferencesManager.get(PREFERENCE_PROJECT_IMAGE_RIBBON);
PreferencesManager.set(PREFERENCE_PROJECT_IMAGE_RIBBON, !currentEnabled);
return; // Don't dismiss highlights for this option
}

// need to dismiss the previous highlighting and stuff
Expand Down Expand Up @@ -1318,15 +1296,8 @@ define(function (require, exports, module) {
LiveDevelopment.updateElementHighlightConfig();
});

// Handle image ribbon preference changes from this extension
PreferencesManager.on("change", PREFERENCE_PROJECT_IMAGE_RIBBON, function() {
LiveDevelopment.updateImageRibbonConfig();
});

// Initialize element highlight config on startup
LiveDevelopment.updateElementHighlightConfig();
// Initialize image ribbon config on startup
LiveDevelopment.updateImageRibbonConfig();

LiveDevelopment.openLivePreview();
LiveDevelopment.on(LiveDevelopment.EVENT_OPEN_PREVIEW_URL, _openLivePreviewURL);
Expand Down
32 changes: 32 additions & 0 deletions src/htmlContent/image-folder-dialog.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<div class="image-folder-dialog template modal">
<div class="modal-header">
<h1 class="dialog-title">{{Strings.LIVE_DEV_IMAGE_FOLDER_DIALOG_TITLE}}</h1>
</div>
<div class="modal-body">
<p>{{Strings.LIVE_DEV_IMAGE_FOLDER_DIALOG_DESCRIPTION}}</p>
<input type="text"
id="folder-path-input"
placeholder="{{Strings.LIVE_DEV_IMAGE_FOLDER_DIALOG_PLACEHOLDER}}"
value=""
autocomplete="off"
spellcheck="false">

<!-- the folder suggestions will come here dynamically -->
<div id="folder-suggestions"></div>

<p class="folder-help-text">
{{Strings.LIVE_DEV_IMAGE_FOLDER_DIALOG_HELP}}
</p>

<div class="remember-folder-container">
<label>
<input type="checkbox" id="remember-folder-checkbox" checked>
<span>{{Strings.LIVE_DEV_IMAGE_FOLDER_DIALOG_REMEMBER}}</span>
</label>
</div>
</div>
<div class="modal-footer">
<button class="dialog-button btn" data-button-id="cancel">{{Strings.CANCEL}}</button>
<button class="dialog-button btn primary" data-button-id="ok">{{Strings.OK}}</button>
</div>
</div>
14 changes: 12 additions & 2 deletions src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,17 +189,27 @@ define({
"LIVE_DEV_MORE_OPTIONS_DUPLICATE": "Duplicate",
"LIVE_DEV_MORE_OPTIONS_DELETE": "Delete",
"LIVE_DEV_MORE_OPTIONS_AI": "Edit with AI",
"LIVE_DEV_MORE_OPTIONS_IMAGE_GALLERY": "Image Gallery",
"LIVE_DEV_IMAGE_GALLERY_USE_IMAGE": "Use this image",
"LIVE_DEV_IMAGE_GALLERY_SELECT_FROM_COMPUTER": "Select image from computer",
"LIVE_DEV_IMAGE_GALLERY_CHOOSE_FOLDER": "Choose download folder",
"LIVE_DEV_IMAGE_GALLERY_SELECT_DOWNLOAD_FOLDER": "Choose image download folder",
"LIVE_DEV_IMAGE_GALLERY_SEARCH_PLACEHOLDER": "Search images...",
"LIVE_DEV_IMAGE_GALLERY_SEARCH_BUTTON": "Search",
"LIVE_DEV_IMAGE_GALLERY_LOADING_INITIAL": "Loading images...",
"LIVE_DEV_IMAGE_GALLERY_LOADING_MORE": "Loading...",
"LIVE_DEV_IMAGE_GALLERY_NO_IMAGES": "No images found",
"LIVE_DEV_IMAGE_GALLERY_LOAD_ERROR": "Failed to load images",
"LIVE_DEV_IMAGE_FOLDER_DIALOG_TITLE": "Select Folder to Save Image",
"LIVE_DEV_IMAGE_FOLDER_DIALOG_DESCRIPTION": "Choose where to download the image:",
"LIVE_DEV_IMAGE_FOLDER_DIALOG_PLACEHOLDER": "Type folder path (e.g., assets/images/)",
"LIVE_DEV_IMAGE_FOLDER_DIALOG_HELP": "💡 Type folder path or leave empty to download in project root",
"LIVE_DEV_IMAGE_FOLDER_DIALOG_REMEMBER": "Don't ask again for this project",
"LIVE_DEV_AI_PROMPT_PLACEHOLDER": "Ask Phoenix AI to modify this element...",
"LIVE_PREVIEW_CUSTOM_SERVER_BANNER": "Getting preview from your custom server {0}",
"LIVE_PREVIEW_MODE_PREVIEW": "Preview Mode",
"LIVE_PREVIEW_MODE_HIGHLIGHT": "Highlight Mode",
"LIVE_PREVIEW_MODE_EDIT": "Edit Mode",
"LIVE_PREVIEW_EDIT_HIGHLIGHT_ON": "Edit Highlights on Hover",
"LIVE_PREVIEW_EDIT_IMAGE_RIBBON": "Show Image Picker on Image click",
"LIVE_PREVIEW_MODE_PREFERENCE": "{0} shows only the webpage, {1} connects the webpage to your code - click on elements to jump to their code and vice versa, {2} provides highlighting along with advanced element manipulation",
"LIVE_PREVIEW_CONFIGURE_MODES": "Configure Live Preview Modes",
"LIVE_PREVIEW_PRO_FEATURE_TITLE": "Pro Feature",
Expand Down
105 changes: 105 additions & 0 deletions src/styles/brackets_patterns_override.less
Original file line number Diff line number Diff line change
Expand Up @@ -2518,3 +2518,108 @@ code {
}
}
}

// image folder selection dialog
.image-folder-dialog {
#folder-path-input {
width: 100%;
height: 30px;
padding: 5px;
box-sizing: border-box;
margin-bottom: 8px;
}

#folder-suggestions {
max-height: 150px;
overflow-y: auto;
overflow-x: hidden;
border: 1px solid @bc-btn-border;
border-radius: @bc-border-radius;
background-color: @bc-panel-bg-alt;

.dark & {
border: 1px solid @dark-bc-btn-border;
background-color: @dark-bc-panel-bg-alt;
}

&:empty {
display: none;
}

.folder-suggestions-list {
margin: 0;
padding: 0;
list-style: none;
}

.folder-suggestion-item {
padding: 6px 10px;
cursor: pointer;
font-size: 12px;
color: @bc-text;
border-left: 3px solid transparent;

.dark & {
color: @dark-bc-text;
}

&:hover {
background-color: @bc-panel-bg-hover-alt;

.dark & {
background-color: @dark-bc-panel-bg-hover-alt;
}
}

&.selected {
background-color: @bc-bg-highlight;
border-left-color: @bc-primary-btn-bg;

.dark & {
background-color: @dark-bc-bg-highlight;
border-left-color: @dark-bc-primary-btn-bg;
}
}
}

.folder-match-highlight {
font-weight: @font-weight-semibold;
color: @bc-primary-btn-bg;

.dark & {
color: @dark-bc-primary-btn-bg;
}
}
}

.folder-help-text {
margin-top: 8px;
margin-bottom: 0;
font-size: 11px;
color: @bc-text-quiet;
user-select: none;

.dark & {
color: @dark-bc-text-quiet;
}
}

.remember-folder-container {
display: flex;
justify-content: right;
}

.remember-folder-container label {
font-size: 12px;
letter-spacing: 0.3px;
color: @bc-text-quiet;

.dark & {
color: @dark-bc-text-quiet;
}
}

.remember-folder-container input {
margin-top: 2px;
}
}
Loading