mirror of
https://github.com/manilarome/the-glorious-startpage.git
synced 2025-01-05 21:09:07 +01:00
web menu gui and backend
This commit is contained in:
parent
b117869435
commit
bef2769676
@ -15,6 +15,7 @@
|
||||
@import url('theme-engine.css');
|
||||
@import url('weather-screen.css');
|
||||
@import url('weather-settings.css');
|
||||
@import url('web-menu.css');
|
||||
|
||||
:root {
|
||||
/* Colors */
|
||||
|
245
css/web-menu.css
Normal file
245
css/web-menu.css
Normal file
@ -0,0 +1,245 @@
|
||||
#webMenu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background: var(--panel-bg);
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(var(--blur-strength));
|
||||
|
||||
padding-top: 6vh;
|
||||
padding-bottom: 6vh;
|
||||
padding-left: 12vw;
|
||||
padding-right: 12vw;
|
||||
|
||||
/*Dont increase the geometry by using padding*/
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
/*Disable user touch/select on text elements*/
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
/*Transitions*/
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
transition: transform var(--transition-speed),
|
||||
opacity var(--transition-speed),
|
||||
z-index var(--transition-speed);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
#webMenu {
|
||||
padding-top: 6vh;
|
||||
padding-bottom: 0vh;
|
||||
padding-left: 18vw;
|
||||
padding-right: 18vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-height: 799px) {
|
||||
#webMenu {
|
||||
padding-top: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
/*Show web menu*/
|
||||
.showWebMenu {
|
||||
transform: scale(1) !important;
|
||||
opacity: 1 !important;
|
||||
z-index: 3 !important;
|
||||
}
|
||||
|
||||
#webMenuContainer {
|
||||
background: transparent;
|
||||
max-height: 100%;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#webMenuSearchBox {
|
||||
background: var(--base-container);
|
||||
|
||||
text-align: center;
|
||||
font-family: roboto-bold;
|
||||
color: var(--panel-color);
|
||||
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
|
||||
width: 25%;
|
||||
height: 36px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
#webMenuSearchBox {
|
||||
width: 50vw;
|
||||
}
|
||||
}
|
||||
|
||||
#webMenuSearchBoxContainer {
|
||||
/*Center horizontally*/
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
align-items: center;
|
||||
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/*Web menu list*/
|
||||
|
||||
/*UL*/
|
||||
#webMenuList {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
text-align: justify;
|
||||
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/*List*/
|
||||
#webMenuList li {
|
||||
/*Align list horizontally*/
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
#webMenuList li {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
#webMenuList li.selected {
|
||||
background: var(--base-active-bg);
|
||||
border-radius: var(--rounded-radius);
|
||||
transition: transform var(--transition-speed);
|
||||
}
|
||||
|
||||
/*Child of li*/
|
||||
.webItem {
|
||||
background: transparent;
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
margin: 5px;
|
||||
cursor: pointer;
|
||||
border-radius: var(--rounded-radius);
|
||||
}
|
||||
|
||||
.webItem:hover {
|
||||
background: var(--base-hover-bg);
|
||||
}
|
||||
|
||||
.webItem:active {
|
||||
background: var(--base-active-bg);
|
||||
}
|
||||
|
||||
.webItemFocus {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
margin: 5px;
|
||||
border-radius: var(--rounded-radius);
|
||||
background: var(--base-hover-bg);
|
||||
}
|
||||
|
||||
.webItemFocus:hover {
|
||||
background: var(--base-hover-bg);
|
||||
}
|
||||
|
||||
.webItemFocus:active {
|
||||
background: var(--base-active-bg);
|
||||
}
|
||||
|
||||
/*Contains web icon and label*/
|
||||
.webItemContainer {
|
||||
/*Align vertically*/
|
||||
margin:0 auto;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
|
||||
/*Align horizontally*/
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/*Web icon container*/
|
||||
.webItemIconContainer {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.webItemIcon {
|
||||
height: 64px;
|
||||
width: 64px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/*Web label/name*/
|
||||
.webItemName {
|
||||
text-align: center;
|
||||
font-size: 11pt;
|
||||
font-family: roboto;
|
||||
word-wrap: break-word;
|
||||
color: var(--base-color);
|
||||
|
||||
}
|
||||
|
||||
#webMenuListContainer {
|
||||
position: relative;
|
||||
max-height: 70vh;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
overflow-y: scroll;
|
||||
/*scrollbar-width: none !important;
|
||||
-ms-overflow-style: none !important;*/
|
||||
|
||||
/*Fade transparency*/
|
||||
/*-webkit-mask-image: linear-gradient(to bottom, black 85%, transparent 100%);*/
|
||||
/*mask-image: linear-gradient(to bottom, black 85%, transparent 100%);*/
|
||||
}
|
||||
|
||||
/*Hide scrollbar*/
|
||||
/*#webMenuListContainer::-webkit-scrollbar {
|
||||
display: none;
|
||||
}*/
|
||||
|
||||
/*Stretch list item if screen width < 580px*/
|
||||
@media screen and (max-width: 580px) {
|
||||
#webMenuList {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.webItem {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.webItem:hover {
|
||||
-ms-transform: scale(1);
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.webItemFocus {
|
||||
-ms-transform: scale(1);
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
18
index.html
18
index.html
@ -167,9 +167,6 @@
|
||||
</div>
|
||||
<div class="dashboardOverlay" id="dashboardOverlay"></div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Weather screen -->
|
||||
<div id="weatherScreen">
|
||||
<div id="weatherScreenContainer">
|
||||
@ -203,7 +200,21 @@
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Web menu panel -->
|
||||
<div id="webMenu">
|
||||
<div id="webMenuContainer">
|
||||
<div id="webMenuSearchBoxContainer">
|
||||
<input type="text" id="webMenuSearchBox" autocomplete="off" placeholder="Type to search">
|
||||
</div>
|
||||
<div id="webMenuListContainer">
|
||||
|
||||
<ul id="webMenuList">
|
||||
<!-- Javascript will generate a list here -->
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="js/body-background-set.js"></script>
|
||||
@ -219,5 +230,6 @@
|
||||
<script src="js/theme-engine.js"></script>
|
||||
<script src="js/weather-screen.js"></script>
|
||||
<script src="js/weather-settings.js"></script>
|
||||
<script src="js/web-menu.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -25,11 +25,11 @@ const hideDashboard = () => {
|
||||
const toggleDashboard = () => {
|
||||
|
||||
if (rightDashboardVisibility) {
|
||||
// Hide search box
|
||||
// Hide dashboard
|
||||
hideDashboard();
|
||||
|
||||
} else {
|
||||
// Show search box
|
||||
// Show dashboard
|
||||
showDashboard();
|
||||
}
|
||||
|
||||
|
@ -66,8 +66,8 @@ const populateDock = () => {
|
||||
'Launch',
|
||||
'launch',
|
||||
() => {
|
||||
// Toggle web pad
|
||||
alert('toggle web pad');
|
||||
// Toggle web menu
|
||||
toggleWebMenu();
|
||||
}
|
||||
);
|
||||
|
||||
|
341
js/web-menu.js
Normal file
341
js/web-menu.js
Normal file
@ -0,0 +1,341 @@
|
||||
var webMenu = document.getElementById("webMenu");
|
||||
var webMenuList = document.getElementById("webMenuList");
|
||||
var webMenuListContainer = document.getElementById("webMenuListContainer");
|
||||
var webMenuSearchBox = document.getElementById("webMenuSearchBox");
|
||||
|
||||
let webMenuVisibility = false;
|
||||
|
||||
let webItemFocus;
|
||||
let webListIndex = 0;
|
||||
|
||||
// Create mouse event for passed li
|
||||
const createMouseUpEvent = (li, url) => {
|
||||
// Create a callback property for the passed li
|
||||
li.callback = () => {
|
||||
window.location.href = encodeURI(url);
|
||||
}
|
||||
|
||||
// Create onmouseup event for the li
|
||||
li.onmouseup = () => {
|
||||
li.callback();
|
||||
}
|
||||
}
|
||||
|
||||
// Sort list alphabetically
|
||||
const sortList = () => {
|
||||
Array.from(webMenuList.getElementsByTagName("li"))
|
||||
.sort((a, b) => a.textContent.localeCompare(b.textContent))
|
||||
.forEach(li => webMenuList.appendChild(li));
|
||||
}
|
||||
|
||||
// Populate web menu
|
||||
const populateWebMenu = () => {
|
||||
|
||||
// Generate a list
|
||||
for (i = 0; i < (webSites.length); i++) {
|
||||
|
||||
var site = webSites[i].site;
|
||||
var icon = webSites[i].icon;
|
||||
var url = webSites[i].url;
|
||||
|
||||
var li = document.createElement('li');
|
||||
|
||||
// Add mouseup event
|
||||
createMouseUpEvent(li, url);
|
||||
|
||||
// Create an outer div, child of li
|
||||
let webItemDiv = document.createElement('div')
|
||||
webItemDiv.className = 'webItem';
|
||||
// webItemDiv.tabitemIndex = '1';
|
||||
webItemDiv.id = "id" + site;
|
||||
|
||||
// Create a second div, webItemContainer
|
||||
var webItemContainer = document.createElement('div');
|
||||
webItemContainer.className = 'webItemContainer';
|
||||
|
||||
// Create the innermost div, contains icon and label
|
||||
var webItemBody = document.createElement('div');
|
||||
webItemBody.className = 'webItemBody';
|
||||
|
||||
// Create div for webItemIcon
|
||||
var webItemIconContainer = document.createElement('div');
|
||||
webItemIconContainer.className = 'webItemIconContainer';
|
||||
|
||||
var webItemIcon = document.createElement('div');
|
||||
webItemIcon.className = 'webItemIcon';
|
||||
webItemIcon.style.background = "url('assets/webcons/" + icon + ".svg')";
|
||||
webItemIcon.style.backgroundSize = 'cover';
|
||||
|
||||
// Create webItemName
|
||||
var webItemName = document.createElement('div');
|
||||
webItemName.className = 'webItemName';
|
||||
webItemName.innerHTML = site;
|
||||
|
||||
// Append divs with heirarchy
|
||||
webItemDiv.appendChild(webItemContainer);
|
||||
webItemContainer.appendChild(webItemBody);
|
||||
|
||||
webItemIconContainer.appendChild(webItemIcon);
|
||||
webItemBody.appendChild(webItemIconContainer);
|
||||
webItemBody.appendChild(webItemName);
|
||||
|
||||
li.appendChild(webItemDiv);
|
||||
webMenuList.appendChild(li);
|
||||
}
|
||||
|
||||
// Call to sort list
|
||||
sortList();
|
||||
}
|
||||
|
||||
// Fuzzy search
|
||||
String.prototype.fuzzy = (term, ratio) => {
|
||||
var string = this.toLowerCase();
|
||||
var compare = term.toLowerCase();
|
||||
var matches = 0;
|
||||
|
||||
if (string.indexOf(compare) > -1) return true; // covers basic partial matches
|
||||
for (var i = 0; i < compare.length; i++) {
|
||||
string.indexOf(compare[i]) > -1 ? matches += 1 : matches -=1;
|
||||
}
|
||||
return (matches/this.length >= ratio || term == "");
|
||||
};
|
||||
|
||||
// Search through the list
|
||||
const filterWebList = () => {
|
||||
|
||||
var input, filter, ul, li, a, i, txtValue;
|
||||
|
||||
input = webMenuSearchBox;
|
||||
filter = input.value.toUpperCase();
|
||||
ul = webMenuList;
|
||||
li = ul.getElementsByTagName('li');
|
||||
|
||||
// Loop through all list items, and focus if matches the search query
|
||||
for (i = 0; i < li.length; i++) {
|
||||
|
||||
a = li[i].getElementsByClassName("webItemName")[0];
|
||||
txtValue = a.innerHTML || a.textContent || a.innerText;
|
||||
|
||||
// If an item match, hightlight it and focus
|
||||
// if (txtValue.toUpperCase().indexOf(filter) !== -1) {
|
||||
if (txtValue.toUpperCase().fuzzy(filter, 1) === true) {
|
||||
|
||||
// Unselect/Unhightlight old active
|
||||
var oldWebItemFocus = webItemFocus;
|
||||
var oldWebItemFocusChild = oldWebItemFocus.querySelector('.webItem');
|
||||
oldWebItemFocusChild.classList.remove('webItemFocus');
|
||||
|
||||
// Update webItemFocus
|
||||
webItemFocus = li[i];
|
||||
|
||||
// Update weblistindex
|
||||
webListIndex = i;
|
||||
|
||||
// Get child
|
||||
var webItemFocusChild = webItemFocus.querySelector('.webItem');
|
||||
// Add webItemFocus class to child
|
||||
webItemFocusChild.classList.add('webItemFocus');
|
||||
|
||||
// Scroll focus into active
|
||||
webItemFocus.scrollIntoView();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Type event on web mmenu search box
|
||||
webMenuSearchBox.onkeydown = (event) => {
|
||||
|
||||
// Don't hijack keyboard navigation buttons (up, down, left, right)
|
||||
if ((event.key === 'ArrowRight') || (event.key === 'ArrowDown') ||
|
||||
(event.key === 'ArrowLeft') || (event.key === 'ArrowUp')) return;
|
||||
|
||||
if (event.key === 'Enter' && webItemFocus) {
|
||||
// Run the focused li's callback
|
||||
webItemFocus.callback();
|
||||
|
||||
// Hide web menu
|
||||
// webMenuToggle();
|
||||
|
||||
} else if (event.key === 'Backspace' && webMenuSearchBox.value.length < 1) {
|
||||
// Hide web menu if backspace is pressed and searchbox value is 0
|
||||
// webMenuToggle();
|
||||
|
||||
} else if ((event.key === 'Escape') || (event.key === 'Alt')) {
|
||||
// Ignore escape and alt key
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter
|
||||
filterWebList();
|
||||
}
|
||||
|
||||
// Reset focus on web menu close
|
||||
const focusReset = () => {
|
||||
var oldWebItemFocus = webItemFocus;
|
||||
var oldWebItemFocusChild = oldWebItemFocus.querySelector('.webItem');
|
||||
oldWebItemFocusChild.classList.remove('webItemFocus');
|
||||
webListIndex = 0;
|
||||
}
|
||||
|
||||
// Get first item of ul
|
||||
const getFirstItem = () => {
|
||||
var ul = webMenuList;
|
||||
var li = ul.getElementsByTagName('li');
|
||||
|
||||
// Focus on first item
|
||||
webItemFocus = li[0];
|
||||
|
||||
// Get child
|
||||
var webItemFocusChildren = webItemFocus.querySelector('.webItem');
|
||||
|
||||
// Add webItemFocus class
|
||||
webItemFocusChildren.classList.add('webItemFocus');
|
||||
}
|
||||
|
||||
// Show/Hide web menu
|
||||
// const webMenuToggle = () => {
|
||||
|
||||
// webMenuVisible = !webMenuVisible;
|
||||
|
||||
// hideCenterContainer();
|
||||
// rotateProfile();
|
||||
// webMenu.classList.toggle("show");
|
||||
|
||||
// // Clear and unfocus searchbox
|
||||
// if (!webMenuVisible) {
|
||||
// webMenuSearchBox.value = '';
|
||||
// webMenuSearchBox.blur();
|
||||
// filterWebList();
|
||||
// webMenuListContainer.scrollTop = 0;
|
||||
|
||||
// focusReset();
|
||||
// getFirstItem();
|
||||
// } else {
|
||||
// // Focus
|
||||
// webMenuSearchBox.focus();
|
||||
// }
|
||||
|
||||
// if(weatherVisible && webMenuVisible) {
|
||||
// weatherToggle();
|
||||
// } else if (floatPanelVisible && webMenuVisible) {
|
||||
// slideDashboard();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
|
||||
const showWebMenu = () => {
|
||||
webMenu.classList.add('showWebMenu');
|
||||
webMenuVisibility = !webMenuVisibility;
|
||||
}
|
||||
|
||||
const hideWebMenu = () => {
|
||||
webMenu.classList.remove('showWebMenu');
|
||||
webMenuVisibility = !webMenuVisibility;
|
||||
}
|
||||
|
||||
const toggleWebMenu = () => {
|
||||
|
||||
// If profile anim is still running,
|
||||
// Return to avoid spam
|
||||
if (profileAnimRunning) return;
|
||||
|
||||
// Rotate profile
|
||||
rotateProfile();
|
||||
|
||||
if (webMenuVisibility) {
|
||||
// Hide web menu
|
||||
hideWebMenu();
|
||||
|
||||
} else {
|
||||
// Show Web menu
|
||||
showWebMenu();
|
||||
}
|
||||
console.log('toggle web menu');
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Remove class to focused item
|
||||
const removeClass = (el, className) => {
|
||||
// Remove webItemFocus class
|
||||
var oldWebItemFocus = el.querySelector('.webItem');
|
||||
oldWebItemFocus.classList.remove('webItemFocus');
|
||||
};
|
||||
|
||||
// Add class to focused item
|
||||
const addClass = (el, className) => {
|
||||
var webItemFocusChild = el.querySelector('.webItem');
|
||||
|
||||
// Add webItemFocus class to child
|
||||
webItemFocusChild.classList.add('webItemFocus');
|
||||
|
||||
// Scroll focus into active
|
||||
webItemFocusChild.scrollIntoView();
|
||||
};
|
||||
|
||||
// Keyboard navigation
|
||||
webMenu.addEventListener(
|
||||
'keydown',
|
||||
(event) => {
|
||||
var len = webMenuList.getElementsByTagName('li').length - 1;
|
||||
// Right and Down
|
||||
if((event.which === 39) || (event.which === 40)) {
|
||||
|
||||
// Clear web menu searchbox
|
||||
webMenuSearchBox.value = '';
|
||||
webListIndex++;
|
||||
if (webItemFocus) {
|
||||
removeClass(webItemFocus, 'webItemFocus');
|
||||
next = webMenuList.getElementsByTagName('li')[webListIndex];
|
||||
if(typeof next !== undefined && webListIndex <= len) {
|
||||
webItemFocus = next;
|
||||
} else {
|
||||
webListIndex = 0;
|
||||
webItemFocus = webMenuList.getElementsByTagName('li')[0];
|
||||
}
|
||||
addClass(webItemFocus, 'webItemFocus');
|
||||
// console.log(webListIndex);
|
||||
} else {
|
||||
webListIndex = 0;
|
||||
webItemFocus = webMenuList.getElementsByTagName('li')[0];
|
||||
addClass(webItemFocus, 'webItemFocus');
|
||||
}
|
||||
}
|
||||
// Up and left
|
||||
else if ((event.which === 37) || (event.which === 38)) {
|
||||
|
||||
// Clear web menu searchbox
|
||||
webMenuSearchBox.value = '';
|
||||
if (webItemFocus) {
|
||||
removeClass(webItemFocus, 'webItemFocus');
|
||||
webListIndex--;
|
||||
// console.log(webListIndex);
|
||||
next = webMenuList.getElementsByTagName('li')[webListIndex];
|
||||
if(typeof next !== undefined && webListIndex >= 0) {
|
||||
webItemFocus = next;
|
||||
} else {
|
||||
webListIndex = len;
|
||||
webItemFocus = webMenuList.getElementsByTagName('li')[len];
|
||||
}
|
||||
addClass(webItemFocus, 'webItemFocus');
|
||||
} else {
|
||||
webListIndex = 0;
|
||||
webItemFocus = webMenuList.getElementsByTagName('li')[len];
|
||||
addClass(webItemFocus, 'webItemFocus');
|
||||
}
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Populate and get first child
|
||||
const initWebMenu = () => {
|
||||
populateWebMenu();
|
||||
getFirstItem();
|
||||
}
|
||||
|
||||
// Initialize web menu
|
||||
window.onload = initWebMenu();
|
Loading…
Reference in New Issue
Block a user