diff --git a/src/images/icons/star_orange.svg b/src/images/icons/star_orange.svg new file mode 100644 index 00000000..7be1447a --- /dev/null +++ b/src/images/icons/star_orange.svg @@ -0,0 +1,6 @@ + + + Layer 1 + + + \ No newline at end of file diff --git a/src/images/icons/star_orange_stroke.svg b/src/images/icons/star_orange_stroke.svg new file mode 100644 index 00000000..71fe5fe7 --- /dev/null +++ b/src/images/icons/star_orange_stroke.svg @@ -0,0 +1,6 @@ + + + Layer 1 + + + \ No newline at end of file diff --git a/src/images/icons/star_transparent.svg b/src/images/icons/star_transparent.svg new file mode 100644 index 00000000..a1b233d5 --- /dev/null +++ b/src/images/icons/star_transparent.svg @@ -0,0 +1,6 @@ + + + Layer 1 + + + \ No newline at end of file diff --git a/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js b/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js index 9f110bf1..cbf4e075 100644 --- a/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js +++ b/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js @@ -1,13 +1,14 @@ 'use strict'; class PresetsDetailedDialog { - constructor(domDialog, pickedPresetList, onPresetPickedCallback) { + constructor(domDialog, pickedPresetList, onPresetPickedCallback, favoritePresets) { this._domDialog = domDialog; this._pickedPresetList = pickedPresetList; this._finalDialogYesNoSettings = {}; this._onPresetPickedCallback = onPresetPickedCallback; this._openPromiseResolve = undefined; this._isDescriptionHtml = false; + this._favoritePresets = favoritePresets; } load() { @@ -71,7 +72,8 @@ class PresetsDetailedDialog { } this._titlePanel.empty(); - const titlePanel = new PresetTitlePanel(this._titlePanel, this._preset, false, () => this._setLoadingState(false)); + const titlePanel = new PresetTitlePanel(this._titlePanel, this._preset, false, + () => this._setLoadingState(false), this._favoritePresets); titlePanel.load(); this._loadOptionsSelect(); this._updateFinalCliText(); diff --git a/src/tabs/presets/FavoritePresets.js b/src/tabs/presets/FavoritePresets.js index f5799ba5..9693d7d5 100644 --- a/src/tabs/presets/FavoritePresets.js +++ b/src/tabs/presets/FavoritePresets.js @@ -53,6 +53,16 @@ class FavoritePresetsData { return preset; } + delete(presetPath) { + const index = this._favoritePresetsList.findIndex((preset) => preset.presetPath === presetPath); + + if (index >= 0) { + this._favoritePresetsList.splice(index, 1); + this._sort(); + this._purgeOldPresets(); + } + } + findPreset(presetPath) { return this._favoritePresetsList.find((preset) => preset.presetPath === presetPath); } @@ -69,6 +79,11 @@ class FavoritePresetsClass { preset.lastPickDate = favoritePreset.lastPickDate; } + delete(preset) { + this._favoritePresetsData.delete(preset.fullPath); + preset.lastPickDate = undefined; + } + addLastPickDate(presets) { for (let preset of presets) { let favoritePreset = this._favoritePresetsData.findPreset(preset.fullPath); diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanel.css b/src/tabs/presets/TitlePanel/PresetTitlePanel.css index bdd086d6..e9481d12 100644 --- a/src/tabs/presets/TitlePanel/PresetTitlePanel.css +++ b/src/tabs/presets/TitlePanel/PresetTitlePanel.css @@ -1,5 +1,6 @@ .preset_title_panel { color: var(--defaultText); + position: relative; } .preset_title_panel_border { @@ -14,11 +15,26 @@ .preset_title_panel_title { font-size: 1.5em; font-weight: bold; - display: block; + display: inline-block; margin-bottom: 1ex; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + width: calc(100% - 30px); +} + +.preset_title_panel_star { + background-image: url(../../../images/icons/star_orange.svg); + width: 25px; + height: 25px; + background-size: cover; + border-radius: 5px; + padding: 5px; + background-origin: content-box; + background-repeat: no-repeat; + position: absolute; + right: -6px; + top: -5px; } .preset_title_panel_category { diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanel.js b/src/tabs/presets/TitlePanel/PresetTitlePanel.js index ec2b66f5..8c49760d 100644 --- a/src/tabs/presets/TitlePanel/PresetTitlePanel.js +++ b/src/tabs/presets/TitlePanel/PresetTitlePanel.js @@ -2,7 +2,7 @@ class PresetTitlePanel { - constructor(parentDiv, preset, clickable, onLoadedCallback) + constructor(parentDiv, preset, clickable, onLoadedCallback, favoritePresets) { PresetTitlePanel.s_panelCounter ++; this._parentDiv = parentDiv; @@ -10,16 +10,45 @@ class PresetTitlePanel this._domId = `preset_title_panel_${PresetTitlePanel.s_panelCounter}`; this._preset = preset; this._clickable = clickable; + this._favoritePresets = favoritePresets; this._parentDiv.append(`
`); this._domWrapperDiv = $(`.${this._domId}`); this._domWrapperDiv.toggle(false); + this._starJustClicked = false; + this._mouseOnStar = false; + this._mouseOnPanel = false; + this._clickable = clickable; if (clickable) { this._domWrapperDiv.addClass("preset_title_panel_border"); // setting up hover effect here, because if setup in SCC it stops working after background animation like - this._domWrapperDiv.animate({ backgroundColor.... - this._domWrapperDiv.on("mouseenter", () => this._domWrapperDiv.css({"background-color": "var(--subtleAccent)"})); - this._domWrapperDiv.on("mouseleave", () => this._domWrapperDiv.css({"background-color": "var(--boxBackground)"})); + } + } + + _updateHoverEffects() { + let starMouseHover = false; + + if (this._clickable && this._mouseOnPanel && !this._mouseOnStar) { + this._domWrapperDiv.css({"background-color": "var(--subtleAccent)"}); + } else { + this._domWrapperDiv.css({"background-color": "var(--boxBackground)"}); + } + + if (this._mouseOnStar || (this._mouseOnPanel && this._clickable)) { + this._domStar.css({"background-color": "var(--subtleAccent)"}); + starMouseHover = true; + } else { + this._domWrapperDiv.css({"background-color": "var(--boxBackground)"}); + this._domStar.css({"background-color": "var(--boxBackground)"}); + } + + if (this._preset.lastPickDate) { + this._domStar.css("background-image", "url('../../../images/icons/star_orange.svg')"); + } else if (starMouseHover) { + this._domStar.css("background-image", "url('../../../images/icons/star_orange_stroke.svg')"); + } else { + this._domStar.css("background-image", "url('../../../images/icons/star_transparent.svg')"); } } @@ -30,14 +59,24 @@ class PresetTitlePanel subscribeClick(presetsDetailedDialog, presetsRepo) { this._domWrapperDiv.on("click", () => { - presetsDetailedDialog.open(this._preset, presetsRepo).then(isPresetPicked => { - if (isPresetPicked) { - const color = this._domWrapperDiv.css( "background-color" ); - this._domWrapperDiv.css('background-color', 'green'); - this._domWrapperDiv.animate({ backgroundColor: color }, 2000); - this.setPicked(true); - } - }); + if (!this._starJustClicked) { + this._showPresetsDetailedDialog(presetsDetailedDialog, presetsRepo); + } + + this._starJustClicked = false; + }); + } + + _showPresetsDetailedDialog(presetsDetailedDialog, presetsRepo) { + presetsDetailedDialog.open(this._preset, presetsRepo).then(isPresetPicked => { + if (isPresetPicked) { + const color = this._domWrapperDiv.css( "background-color" ); + this._domWrapperDiv.css('background-color', 'green'); + this._domWrapperDiv.animate({ backgroundColor: color }, 2000); + this.setPicked(true); + } + + this._updateHoverEffects(); }); } @@ -70,6 +109,12 @@ class PresetTitlePanel this._domStatusCommunity.toggle(this._preset.status === "COMMUNITY"); this._domStatusExperimental.toggle(this._preset.status === "EXPERIMENTAL"); this.setPicked(this._preset.isPicked); + this._setupStar(); + + this._domWrapperDiv.on("mouseenter", () => { this._mouseOnPanel = true; this._updateHoverEffects(); }); + this._domWrapperDiv.on("mouseleave", () => { this._mouseOnPanel = false; this._updateHoverEffects(); } ); + this._domStar.on("mouseenter", () => { this._mouseOnStar = true; this._updateHoverEffects(); }); + this._domStar.on("mouseleave", () => { this._mouseOnStar = false; this._updateHoverEffects(); }); i18n.localizePage(); this._domWrapperDiv.toggle(true); @@ -79,6 +124,7 @@ class PresetTitlePanel _readDom() { this._domTitle = this._domWrapperDiv.find('.preset_title_panel_title'); + this._domStar = this._domWrapperDiv.find('.preset_title_panel_star'); this._domCategory = this._domWrapperDiv.find('.preset_title_panel_category'); this._domAuthor = this._domWrapperDiv.find('.preset_title_panel_author_text'); this._domKeywords = this._domWrapperDiv.find('.preset_title_panel_keywords_text'); @@ -88,6 +134,26 @@ class PresetTitlePanel this._domStatusExperimental = this._domWrapperDiv.find('.preset_title_panel_status_experimental'); } + _setupStar() { + this._updateHoverEffects(); + + this._domStar.on("click", () => { + this._starJustClicked = true; + this._processStarClick(); + }); + } + + _processStarClick() { + if (this._preset.lastPickDate) { + this._favoritePresets.delete(this._preset); + } else { + this._favoritePresets.add(this._preset); + } + + this._favoritePresets.saveToStorage(); + this._updateHoverEffects(); + } + remove() { this._domWrapperDiv.remove(); diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html b/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html index 081c53eb..7dd031ba 100644 --- a/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html +++ b/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html @@ -1,4 +1,5 @@
+
diff --git a/src/tabs/presets/presets.js b/src/tabs/presets/presets.js index f5e89656..fd7936e7 100644 --- a/src/tabs/presets/presets.js +++ b/src/tabs/presets/presets.js @@ -269,7 +269,7 @@ presets.onHtmlLoad = function(callback) { this.setupBackupWarning(); this._inputTextFilter.attr("placeholder", "example: \"karate race\", or \"5'' freestyle\""); - this.presetsDetailedDialog = new PresetsDetailedDialog($("#presets_detailed_dialog"), this.pickedPresetList, () => this.onPresetPickedCallback()); + this.presetsDetailedDialog = new PresetsDetailedDialog($("#presets_detailed_dialog"), this.pickedPresetList, () => this.onPresetPickedCallback(), favoritePresets); this.presetsSourcesDialog = new PresetsSourcesDialog($("#presets_sources_dialog")); this.presetsDetailedDialog.load() @@ -460,7 +460,7 @@ presets.displayPresets = function(fitPresets) { this._domListNoFound.toggle(fitPresets.length === 0); fitPresets.forEach(preset => { - const presetPanel = new PresetTitlePanel(this._divPresetList, preset, true); + const presetPanel = new PresetTitlePanel(this._divPresetList, preset, true, undefined, favoritePresets); presetPanel.load(); this._presetPanels.push(presetPanel); presetPanel.subscribeClick(this.presetsDetailedDialog, this.presetsRepo);