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
3 changes: 2 additions & 1 deletion src/brackets.config.dist.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"buildtype" : "production",
"bugsnagEnv" : "production",
"app_notification_url" : "https://updates.phcode.io/appNotifications/prod/",
"app_update_url" : "https://updates.phcode.io/tauri/update-latest-stable-prod.json"
"app_update_url" : "https://updates.phcode.io/tauri/update-latest-stable-prod.json",
"promotions_url" : "https://promotions.phcode.dev/prod/"
}
3 changes: 2 additions & 1 deletion src/brackets.config.staging.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"buildtype" : "staging",
"bugsnagEnv" : "staging",
"app_notification_url" : "https://updates.phcode.io/appNotifications/staging/",
"app_update_url" : "https://updates.phcode.io/tauri/update-latest-pre-release.json"
"app_update_url" : "https://updates.phcode.io/tauri/update-latest-pre-release.json",
"promotions_url" : "https://promotions.phcode.dev/dev/"
}
2 changes: 2 additions & 0 deletions src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"app_name_about": "Phoenix Code",
"about_icon": "styles/images/phoenix-icon.svg",
"account_url": "https://account.phcode.dev/",
"promotions_url": "https://promotions.phcode.dev/dev/",
"purchase_url": "https://phcode.io/pricing",
"how_to_use_url": "https://github.com/adobe/brackets/wiki/How-to-Use-Brackets",
"docs_url": "https://docs.phcode.dev/",
"support_url": "https://account.phcode.dev/?returnUrl=https%3A%2F%2Faccount.phcode.dev%2F%23support",
Expand Down
5 changes: 4 additions & 1 deletion src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1667,6 +1667,7 @@ define({
// promos
"PROMO_UPGRADE_TITLE": "You’ve been upgraded to {0}",
"PROMO_UPGRADE_MESSAGE": "Enjoy full access to all premium features for the next {0} days:",
"PROMO_ENDED_MESSAGE": "Subscribe now to continue using these advanced features:",
"PROMO_CARD_1": "Drag & Drop Elements",
"PROMO_CARD_1_MESSAGE": "Rearrange sections visually — Phoenix updates the HTML & CSS for you.",
"PROMO_CARD_2": "Image Replacement",
Expand All @@ -1675,5 +1676,7 @@ define({
"PROMO_CARD_3_MESSAGE": "Duplicate and delete elements with a single click.",
"PROMO_CARD_4": "Editing Text In Preview",
"PROMO_CARD_4_MESSAGE": "Edit headings, buttons, and copy directly in the preview.",
"PROMO_LEARN_MORE": "Learn More\u2026"
"PROMO_LEARN_MORE": "Learn More\u2026",
"PROMO_GET_APP_UPSELL_BUTTON": "Get {0}",
"PROMO_PRO_ENDED_TITLE": "Your {0} upgrade has ended"
});
6 changes: 3 additions & 3 deletions src/services/html/pro-upgrade.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="browser-login-waiting-dialog modal">
<div class="pro-upgrade-dialog modal">
<div class="modal-header">
<h1 class="dialog-title">{{{title}}}</h1>
</div>
Expand Down Expand Up @@ -50,7 +50,7 @@ <h2>{{Strings.PROMO_CARD_4}}</h2>
</div>

<div class="modal-footer">
<button class="dialog-button btn" data-button-id="learn_more">{{Strings.PROMO_LEARN_MORE}}</button>
<button class="dialog-button btn primary" data-button-id="ok">{{Strings.OK}}</button>
<button class="dialog-button btn" data-button-id="secondaryButton">{{secondaryButton}}</button>
<button class="dialog-button btn primary" data-button-id="ok">{{{primaryButton}}}</button>
</div>
</div>
22 changes: 22 additions & 0 deletions src/services/html/promo-ended.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div class="pro-ended-dialog modal">
<div class="modal-header">
<h1 class="dialog-title">{{{title}}}</h1>
</div>

<div class="modal-body">
<div class="promo-iframe-wrap">
<iframe
class="promo-iframe"
src="{{promoURL}}"
title="{{title}}"
loading="lazy"
referrerpolicy="no-referrer">
</iframe>
</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="get_pro">{{{buttonGetPro}}}</button>
</div>
</div>
2 changes: 1 addition & 1 deletion src/services/login-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ define(function (require, exports, module) {

try {
const accountBaseURL = LoginService.getAccountBaseURL();
const language = Phoenix.app && Phoenix.app.language ? Phoenix.app.language : 'en';
const language = brackets.getLocale();
let url = `${accountBaseURL}/getAppEntitlements?lang=${language}`;
let fetchOptions = {
method: 'GET',
Expand Down
92 changes: 87 additions & 5 deletions src/services/pro-dialogs.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,107 @@ define(function (require, exports, module) {
const proTitle = `<span class="phoenix-pro-title">
<span class="pro-plan-name">Phoenix Pro</span>
<i class="fa-solid fa-feather orange-gold" style="margin-left: 3px;"></i>
</span>`;
</span>`,
proTitlePlain = `<span class="pro-plan-name">Phoenix Pro</span>
<i class="fa-solid fa-feather" style="margin-left: 2px;"></i>`;
require("./setup-login-service"); // this adds loginService to KernalModeTrust
const Dialogs = require("widgets/Dialogs"),
Mustache = require("thirdparty/mustache/mustache"),
Strings = require("strings"),
StringUtils = require("utils/StringUtils"),
proUpgradeHTML = require("text!./html/pro-upgrade.html");
ThemeManager = require("view/ThemeManager"),
Metrics = require("utils/Metrics"),
proUpgradeHTML = require("text!./html/pro-upgrade.html"),
proEndedHTML = require("text!./html/promo-ended.html");

function showProUpgradeDialog(trialDays) {
const title = StringUtils.format(Strings.PROMO_UPGRADE_TITLE, proTitle);
const message = StringUtils.format(Strings.PROMO_UPGRADE_MESSAGE, trialDays);
const $template = $(Mustache.render(proUpgradeHTML, {title, message, Strings}));
const $template = $(Mustache.render(proUpgradeHTML, {
title, message, Strings,
secondaryButton: Strings.PROMO_LEARN_MORE,
primaryButton: Strings.OK
}));
Dialogs.showModalDialogUsingTemplate($template).done(function (id) {
console.log("Dialog closed with id: " + id);
if(id === 'learn_more') {
Phoenix.app.openURLInDefaultBrowser(brackets.config.homepage_url);
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgShow", "promo");
if(id === 'secondaryButton') {
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgAct", "promoLearn");
Phoenix.app.openURLInDefaultBrowser(brackets.config.purchase_url);
} else {
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgAct", "promoCancel");
}
});
}

function _showLocalProEndedDialog() {
const title = StringUtils.format(Strings.PROMO_PRO_ENDED_TITLE, proTitle);
const buttonGetPro = StringUtils.format(Strings.PROMO_GET_APP_UPSELL_BUTTON, proTitlePlain);
const $template = $(Mustache.render(proUpgradeHTML, {
title, Strings,
message: Strings.PROMO_ENDED_MESSAGE,
secondaryButton: Strings.CANCEL,
primaryButton: buttonGetPro
}));
Dialogs.showModalDialogUsingTemplate($template).done(function (id) {
console.log("Dialog closed with id: " + id);
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgShow", "localUpgrade");
if(id === 'ok') {
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgAct", "localGetPro");
Phoenix.app.openURLInDefaultBrowser(brackets.config.purchase_url);
} else {
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgAct", "localCancel");
}
});
}

function _showRemoteProEndedDialog(currentVersion, promoHtmlURL, upsellPurchaseURL) {
const buttonGetPro = StringUtils.format(Strings.PROMO_GET_APP_UPSELL_BUTTON, proTitlePlain);
const title = StringUtils.format(Strings.PROMO_PRO_ENDED_TITLE, proTitle);
const currentTheme = ThemeManager.getCurrentTheme();
const theme = currentTheme && currentTheme.dark ? "dark" : "light";
const promoURL = `${promoHtmlURL}?lang=${
brackets.getLocale()}&theme=${theme}&version=${currentVersion}`;
const $template = $(Mustache.render(proEndedHTML, {Strings, title, buttonGetPro, promoURL}));
Dialogs.showModalDialogUsingTemplate($template).done(function (id) {
console.log("Dialog closed with id: " + id);
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgShow", "remoteUpgrade");
if(id === 'get_pro') {
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgAct", "remoteGetPro");
Phoenix.app.openURLInDefaultBrowser(upsellPurchaseURL || brackets.config.purchase_url);
} else {
Metrics.countEvent(Metrics.EVENT_TYPE.PRO, "dlgAct", "remoteCancel");
}
});
}

async function showProEndedDialog() {
const currentVersion = window.AppConfig.apiVersion;

if (!navigator.onLine) {
_showLocalProEndedDialog();
return;
}

try {
const configURL = `${brackets.config.promotions_url}app/config.json`;
const response = await fetch(configURL);
if (!response.ok) {
_showLocalProEndedDialog();
return;
}

const config = await response.json();
if (config.upsell_after_trial_url) {
_showRemoteProEndedDialog(currentVersion, config.upsell_after_trial_url, config.upsell_purchase_url);
} else {
_showLocalProEndedDialog();
}
} catch (error) {
_showLocalProEndedDialog();
}
}

exports.showProUpgradeDialog = showProUpgradeDialog;
exports.showProEndedDialog = showProEndedDialog;
});
1 change: 0 additions & 1 deletion src/services/profile-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,6 @@ define(function (require, exports, module) {
title: Strings.CMD_USER_PROFILE
})
.appendTo($("#main-toolbar .bottom-buttons"));
// _updateProfileIcon("CA", "blue");
$icon.on('click', ()=>{
togglePopup();
});
Expand Down
19 changes: 17 additions & 2 deletions src/services/promotions.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,20 @@ define(function (require, exports, module) {

// Check if we should grant any trial
if (remainingDays <= 0 && !isNewerVersion) {
console.log("Existing trial expired, same/older version - no new trial");
// Check if promo ended dialog was already shown for this version
if (existingTrialData.upgradeDialogShownVersion !== currentVersion) {
// todo we should not show this to logged in pro subscribers, but at startup time,
// we do not know if login is done yet.
console.log("Existing trial expired, showing promo ended dialog");
ProDialogs.showProEndedDialog();
// Store that dialog was shown for this version
await _setTrialData({
...existingTrialData,
upgradeDialogShownVersion: currentVersion
});
} else {
console.log("Existing trial expired, upgrade dialog already shown for this version");
}
return;
}

Expand Down Expand Up @@ -253,7 +266,9 @@ define(function (require, exports, module) {

function _isAnyDialogsVisible() {
const $modal = $(`.modal.instance`);
return $modal.length > 0 && $modal.is(':visible');
const $notifications = $(`.notification-ui-tooltip`);
return ($modal.length > 0 && $modal.is(':visible')) ||
($notifications.length > 0 && $notifications.is(':visible'));
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/styles/brackets.less
Original file line number Diff line number Diff line change
Expand Up @@ -3222,6 +3222,7 @@ label input {
flex-direction: column;
z-index: 100;
height: 100%;
pointer-events: none;
}

.notification-popup-container {
Expand All @@ -3237,6 +3238,7 @@ label input {
/* animated properties */
opacity: 0;
transform: translateY(-50px);
pointer-events: all;
}

.notification-dialog-content strong {
Expand Down
1 change: 1 addition & 0 deletions src/styles/brackets_core_ui_variables.less
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
@bc-text-searching-match: #f6a644;

// Panel
@bc-titlebar-modern-gradient: linear-gradient(135deg, rgba(255,154,60,0.12), rgba(20,115,230,0.08));
@bc-panel-bg: #dfe2e2;
@bc-panel-bg-alt: #e6e9e9;
@bc-panel-bg-promoted: #d4d7d7;
Expand Down
3 changes: 1 addition & 2 deletions src/styles/brackets_patterns_override.less
Original file line number Diff line number Diff line change
Expand Up @@ -1071,13 +1071,12 @@ a:focus {
}

.modal-header {
background: @bc-panel-bg-promoted;;
background: @bc-titlebar-modern-gradient;
border-radius: 4px 4px 0 0;
border-bottom: 1px solid @bc-panel-separator;
box-shadow: inset 0 1px 0 @bc-highlight;

.dark & {
background: @dark-bc-panel-bg-promoted;;
border-bottom: 1px solid @dark-bc-panel-separator;
box-shadow: inset 0 1px 0 @dark-bc-highlight;
}
Expand Down
79 changes: 58 additions & 21 deletions src/styles/phoenix-pro.less
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
@import "brackets_variables.less";
@import "brackets_core_ui_variables.less";

/* ---- Phoenix Pro gradient title ----
Light default: use the "light" gradient so it pops on light bg.
Dark override: switch to the "dark" gradient for richer contrast. */
.phoenix-pro-title {
background: @phoenix-pro-gradient-light;
background-clip: text;
-webkit-background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
display: inline-block;

.dark & {
background: @phoenix-pro-gradient-dark;
background-clip: text;
-webkit-background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
}
}

/* Dialog styles with light default + .dark overrides */
.browser-login-waiting-dialog {
.browser-login-waiting-dialog, .pro-upgrade-dialog{
/* ---- Layout ---- */
.features-grid {
display: grid;
Expand Down Expand Up @@ -104,26 +124,6 @@
}
}

/* ---- Phoenix Pro gradient title ----
Light default: use the "light" gradient so it pops on light bg.
Dark override: switch to the "dark" gradient for richer contrast. */
.phoenix-pro-title {
background: @phoenix-pro-gradient-light;
background-clip: text;
-webkit-background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
display: inline-block;

.dark & {
background: @phoenix-pro-gradient-dark;
background-clip: text;
-webkit-background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
}
}

/* ---- Links ---- */
a {
color: @bc-text-link; // #0083e8
Expand All @@ -138,3 +138,40 @@
text-decoration: underline;
}
}

.pro-ended-dialog.modal {
display: flex;
flex-direction: column;
width: 640px;
height: 640px; /* overall modal height */
}

.pro-ended-dialog .modal-header,
.pro-ended-dialog .modal-footer {
flex: 0 0 auto; /* don’t stretch */
}

.pro-ended-dialog .modal-body {
flex: 1 1 auto; /* take all leftover space */
min-height: 0; /* allow shrinking properly */
max-height: 100%; /* allow shrinking properly */
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
background: none;
}

.pro-ended-dialog .promo-iframe-wrap {
flex: 1 1 auto;
min-height: 0; /* important inside flex */
display: flex;
}

.pro-ended-dialog .promo-iframe {
flex: 1 1 auto;
width: 100%;
height: 100%;
border: 0;
display: block;
}
Loading