diff --git a/resources/index.css b/resources/index.css new file mode 100644 index 0000000..3cbb146 --- /dev/null +++ b/resources/index.css @@ -0,0 +1,146 @@ +body { + display: flex; + flex-direction: row; +} + +#service-selector { + flex-grow: 1; + display: block; + margin: 0; + padding: 0; +} + +*:focus { + outline-color: rgb(118, 93, 176); +} + +#navigation button { + display: block; + width: 100%; + padding: 16px; + margin: 0; + height: 72px; + + color: #fff; + border: 0; + background: transparent; + + cursor: pointer; +} + +#navigation button img { + width: 32px; +} + +#navigation button i { + font-size: 32px; +} + +#service-selector li { + position: relative; +} + +#service-selector li.active button { + position: relative; + background-color: #fff2; +} + +#service-selector li.active button::before { + content: ""; + display: block; + position: absolute; + left: 0; + top: 0; + height: 100%; + border-left: 4px solid #ffffff2e; +} + +#service-selector li.loaded::after { + content: ""; + position: absolute; + top: 50%; + right: 2px; + transform: translateY(-50%); + width: 4px; + height: 4px; + + background-color: #fff; + border-radius: 100%; +} + +#navigation button:hover { + background-color: #fff3; +} + +#history { + padding: 8px; +} + +#history button { + display: inline; + width: 24px; + height: 24px; + padding: initial; + font-size: 12px; + + background: #fff1; + border: 1px solid #fff4; + border-radius: 72px; + + color: #fff; + cursor: pointer; +} + +#history button i { + font-size: inherit; +} + +#history button.disabled { + color: #888; + border: transparent; + background: transparent; + cursor: initial; +} + +#history button:focus, +#history button:hover { + outline: none; + border-color: #fff9; +} + +#history button:hover:not(.disabled) { + outline: none; + background-color: #fff2; +} + +#history button:active:not(.disabled) { + background-color: #fff4; +} + +#navigation #add-button:not(:hover) { + opacity: 0.75; +} + +#services { + position: relative; + flex-grow: 1; +} + +#services > *:not(.loader) { + height: 100%; +} + +#services > :not(.active):not(.loader) { + display: none; +} + +#services > .loader { + width: 64px; + height: 64px; + + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + z-index: -1; +} \ No newline at end of file diff --git a/resources/index.html b/resources/index.html index ad4fe07..c5d3d06 100644 --- a/resources/index.html +++ b/resources/index.html @@ -1,144 +1,14 @@ + Tabs - - + @@ -331,6 +201,10 @@ } else { nav.insertBefore(li, nextNavButton); } + + if (service.autoLoad) { + loadService(index, service); + } } document.addEventListener('DOMContentLoaded', () => { @@ -347,34 +221,7 @@ function setActiveService(serviceId) { let currentService = services[serviceId]; process.nextTick(() => { - // Load service if not loaded yet - if (!currentService.view) { - currentService.view = document.createElement('webview'); - currentService.view.setAttribute('src', currentService.url); - currentService.view.setAttribute('partition', 'persist:service_' + currentService.partition); - currentService.view.setAttribute('autosize', "true"); - - document.querySelector('#services').appendChild(currentService.view); - currentService.view.addEventListener('dom-ready', event => { - currentService.viewReady = true; - updateNavigation(); - }); - currentService.view.addEventListener('page-favicon-updated', event => { - console.debug('Loaded favicons for', currentService.name, event.favicons); - if (event.favicons.length > 0) { - ipcRenderer.send('setServiceFavicon', serviceId, event.favicons[0]); - if (currentService.useFavicon) { - const img = document.createElement('img'); - img.src = event.favicons[0]; - img.alt = currentService.name; - img.onload = () => { - currentService.li.button.innerHTML = ''; - currentService.li.button.appendChild(img); - }; - } - } - }); - } + loadService(serviceId, currentService); // Hide previous service if (services[selectedService] && services[selectedService].view) { @@ -392,6 +239,39 @@ }); } + function loadService(serviceId, service) { + // Load service if not loaded yet + if (!service.view) { + service.view = document.createElement('webview'); + service.view.setAttribute('src', service.url); + service.view.setAttribute('partition', 'persist:service_' + service.partition); + service.view.setAttribute('autosize', "true"); + + document.querySelector('#services').appendChild(service.view); + service.view.addEventListener('dom-ready', () => { + service.viewReady = true; + updateNavigation(); + }); + service.view.addEventListener('page-favicon-updated', event => { + console.debug('Loaded favicons for', service.name, event.favicons); + if (event.favicons.length > 0) { + ipcRenderer.send('setServiceFavicon', serviceId, event.favicons[0]); + if (service.useFavicon) { + const img = document.createElement('img'); + img.src = event.favicons[0]; + img.alt = service.name; + img.onload = () => { + service.li.button.innerHTML = ''; + service.li.button.appendChild(img); + }; + } + } + }); + + service.li.classList.add('loaded'); + } + } + function updateNavigation() { console.debug('Updating navigation'); // Update active list element diff --git a/resources/service-settings.html b/resources/service-settings.html index ed2d04b..447a447 100644 --- a/resources/service-settings.html +++ b/resources/service-settings.html @@ -134,6 +134,11 @@ +
+ + +
+

Service icon

@@ -216,27 +221,6 @@ }); }); - function loadServiceValues() { - if (!service || !isImageCheckbox) { - return; - } - - document.getElementById('name').value = service.name; - document.getElementById('url').value = service.url; - document.getElementById('use-favicon').checked = service.useFavicon; - isImageCheckbox.checked = service.isImage; - if (service.isImage) { - iconUrlField.value = service.icon; - } else { - builtInIconSearchField.value = service.icon; - updateIconSearchResults(); - const icon = Array.from(iconSelect.querySelectorAll('label')).find(i => i.dataset.icon === service.icon); - if (icon) { - selectIcon(icon); - } - } - } - function updateIconSearchResults() { const searchStr = builtInIconSearchField.value; iconSelect.childNodes.forEach(c => { @@ -298,6 +282,50 @@ } } + function loadServiceValues() { + if (!service || !isImageCheckbox) { + return; + } + + document.getElementById('name').value = service.name; + document.getElementById('url').value = service.url; + document.getElementById('use-favicon').checked = service.useFavicon; + document.getElementById('auto-load').checked = service.autoLoad; + isImageCheckbox.checked = service.isImage; + if (service.isImage) { + iconUrlField.value = service.icon; + } else { + builtInIconSearchField.value = service.icon; + updateIconSearchResults(); + const icon = Array.from(iconSelect.querySelectorAll('label')).find(i => i.dataset.icon === service.icon); + if (icon) { + selectIcon(icon); + } + } + } + + function save() { + const formData = new FormData(document.querySelector('form')); + service.name = formData.get('name'); + if (typeof service.partition !== 'string' || service.partition.length === 0) { + service.partition = service.name.replace(/ /g, '-'); + service.partition = service.partition.replace(/[^a-zA-Z-_]/g, ''); + } + service.url = formData.get('url'); + service.isImage = formData.get('isImage') === 'on'; + service.icon = formData.get('icon'); + service.useFavicon = formData.get('useFavicon') === 'on'; + service.autoLoad = formData.get('autoLoad') === 'on'; + + + if (!isValid()) { + return; + } + + ipcRenderer.send('saveService', serviceId, service); + remote.getCurrentWindow().close(); + } + function isValid() { if (typeof service.name !== 'string' || service.name.length === 0) { console.log('Invalid name'); @@ -317,27 +345,6 @@ } return true; } - - function save() { - const formData = new FormData(document.querySelector('form')); - service.name = formData.get('name'); - if (typeof service.partition !== 'string' || service.partition.length === 0) { - service.partition = service.name.replace(/ /g, '-'); - service.partition = service.partition.replace(/[^a-zA-Z-_]/g, ''); - } - service.url = formData.get('url'); - service.isImage = formData.get('isImage') === 'on'; - service.icon = formData.get('icon'); - service.useFavicon = formData.get('useFavicon') === 'on'; - - - if (!isValid()) { - return; - } - - ipcRenderer.send('saveService', serviceId, service); - remote.getCurrentWindow().close(); - } \ No newline at end of file diff --git a/src/Service.js b/src/Service.js index d198c55..bf7bd0d 100644 --- a/src/Service.js +++ b/src/Service.js @@ -33,6 +33,7 @@ Service.requiredProperties = { 'isImage': null, 'url': null, 'useFavicon': true, + 'autoLoad': false, }; export default Service; \ No newline at end of file