Rebrand Settings to More

This commit is contained in:
Daniel 2023-10-23 23:32:25 +02:00
parent 1938eb100d
commit 315fb5221d
20 changed files with 356 additions and 289 deletions

View File

@ -26,17 +26,18 @@ Configuration file is located at `config/config.json`. It is pretty readable, so
The following keys are available under `ui` section. Some of them are listed in _Settings_ page and can be overriden by end-user.
| Key name | Description | in Settings |
|-----------------------|---------------------------------------------------------------------------------------|---------------|
| `name` | Name shown at the main screen and the tab title. | ❌ |
| `desc` | Short description shown under title at the main screen. | ❌ |
| `icon` | Icon shown at the main screen and as site's favicon. | ❌ |
| `wallpaper` | Background image visible when dark mode is disabled. | ❌ |
| `wallpaper_dark` | Background image visible when dark mode is enabled. | ❌ |
| `dark_mode` | Tells whether dark mode is enabled by default. | ✅ |
| `open_new_tab` | Tells whether clicking on a service will open it in new tab by default. | ✅ |
| `blur` | Tells whether card background blur is enabled by default. | ✅ |
| `animations` | Tells whether UI animations are enabled by default. | ✅ |
| Key name | Description | in Settings |
|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|---------------|
| `name` | Name shown at the main screen and the tab title. | ❌ |
| `desc` | Short description shown under title at the main screen. | ❌ |
| `icon` | Icon shown at the main screen and as site's favicon. | ❌ |
| `wallpaper` | Background image visible when dark mode is disabled. | ❌ |
| `wallpaper_dark` | Background image visible when dark mode is enabled. | ❌ |
| `dark_mode` | Tells whether dark mode is enabled by default. | ✅ |
| `open_new_tab` | Tells whether clicking on a service will open it in new tab by default. | ✅ |
| `blur` | Tells whether card background blur is enabled by default. | ✅ |
| `animations` | Tells whether UI animations are enabled by default. | ✅ |
| `https_importance` | How important is HTTPS comparing to independence. If set to `0.25`, HTTPS will score maximum 25% in Privacy Panel. Total importance is `1`. | ✅ |
### 🔗 Adding custom services

View File

@ -6,6 +6,10 @@ body.dark {
--hover: #FFF1;
}
body.dark #theme-switcher i::after {
content: "dark_mode"
body.dark #theme-switcher i::before {
--hidden: 1;
}
body.dark #theme-switcher i::after {
--hidden: 0;
}

View File

@ -18,8 +18,30 @@
opacity: 0;
}
#theme-switcher i {
position: relative;
overflow: hidden;
}
#theme-switcher i::before, #theme-switcher i::after {
position: absolute;
top: 50%;
left: 50%;
--hidden: 1;
opacity: calc(1 - var(--hidden));
transform: translate(-50%, -50%) rotateZ(calc(var(--hidden) * 360deg)) scale(calc(1 - var(--hidden) / 2));
transition: transform .3s, opacity .3s;
}
#theme-switcher i::before {
--hidden: 0;
--dark: 0;
content: "light_mode";
}
#theme-switcher i::after {
content: "light_mode"
--dark: 1;
content: "dark_mode";
}
.home.page {

14
css/Pages/More/More.css Normal file
View File

@ -0,0 +1,14 @@
@import url(Privacy.css);
@import url(Settings.css);
.subpages {
position: relative;
transform: translateX(calc(var(--id) * -100%));
transition: transform .4s, height .4s;
}
.subpages > div {
position: absolute;
left: calc(var(--n) * 100%);
width: 100%;
}

View File

@ -0,0 +1,80 @@
#report-boxes {
display: flex;
text-align: left;
flex-wrap: wrap;
margin-bottom: 8px;
}
#report-boxes i::after {
color: var(--color);
text-shadow: 0 0 48px var(--color);
padding: 16px;
font-size: 28px;
border-radius: 32px;
}
#report-boxes .icon-https::after {
--color: #0C7;
content: "lock";
}
#report-boxes .icon-rocket::after {
--color: #68F;
content: "rocket_launch";
}
#report-boxes .prewarn i::after {
--color: #EA0;
}
#report-boxes .warn i::after {
--color: #F60;
}
#report-boxes .error i::after {
--color: #F22;
}
#report-boxes > div {
display: flex;
width: 50%;
min-width: 256px;
flex: 1;
padding: 20px 8px;
align-items: center;
}
#report-boxes .title {
font-size: 16px;
}
#report-boxes .subtitle {
opacity: .6;
}
.security {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 600px;
padding: 24px;
margin: 120px auto 80px;
text-align: right;
}
.security i {
font-size: 80px;
}
.security #report-score {
font-size: 48px;
}
.security #report {
opacity: .6;
}
.score::after {
content: "%";
font-size: 18px;
}

View File

@ -0,0 +1,72 @@
.settings {
margin: 32px auto;
padding: 0 16px;
}
.setting {
background: var(--bg2);
margin: 8px;
padding: 20px;
display: flex;
cursor: pointer;
border-radius: 16px;
align-items: center;
text-align: left;
transition: background .3s;
}
.setting i {
margin-right: 14px;
font-size: 28px;
}
.setting .name {
font-size: 16px;
}
.setting .desc {
opacity: .6;
margin-right: 16px;
}
.setting .switch {
position: relative;
width: 44px;
min-width: 44px;
height: 24px;
background: #8886;
border-radius: 100px;
margin: 0 4px 0 auto;
transition: border .4s, background .3s;
}
.setting .switch:after {
content: "";
position: absolute;
width: 16px;
height: 16px;
background: var(--color);
left: 4px;
top: 50%;
border-radius: 10px;
transform: translateY(-50%);
transition: left .2s, background .3s;
}
.setting.checked .switch {
background-color: #68F;
border-color: #68F;
}
.setting.checked .switch:after {
left: calc(100% - 20px);
}
#no-cookies {
margin: 24px 0 -8px;
color: #F60;
}
#no-cookies.hidden {
display: none;
}

View File

@ -1,6 +1,6 @@
@import url(Home.css);
@import url(Services.css);
@import url(Settings/Settings.css);
@import url(More/More.css);
.page {
position: fixed;

View File

@ -1,165 +0,0 @@
.settings {
margin: 32px auto;
padding: 0 16px;
}
.setting {
background: var(--bg2);
margin: 8px;
padding: 20px;
display: flex;
cursor: pointer;
border-radius: 16px;
align-items: center;
text-align: left;
transition: background .3s;
}
.setting i {
margin-right: 14px;
font-size: 28px;
}
.setting .name {
font-size: 16px;
}
.setting .desc {
opacity: .6;
margin-right: 16px;
}
.setting .switch {
position: relative;
width: 44px;
min-width: 44px;
height: 24px;
background: #8886;
border-radius: 100px;
margin: 0 4px 0 auto;
transition: border .4s, background .3s;
}
.setting .switch:after {
content: "";
position: absolute;
width: 16px;
height: 16px;
background: var(--color);
left: 4px;
top: 50%;
border-radius: 10px;
transform: translateY(-50%);
transition: left .2s, background .3s;
}
.setting.checked .switch {
background-color: #68F;
border-color: #68F;
}
.setting.checked .switch:after {
left: calc(100% - 20px);
}
#no-cookies {
margin: 24px 0 -8px;
color: #F60;
}
#no-cookies.hidden {
display: none;
}
.subpages {
position: relative;
transform: translateX(calc(var(--id) * -100%));
transition: transform .4s, height .4s;
}
.subpages > div {
position: absolute;
left: calc(var(--n) * 100%);
width: 100%;
}
#report-boxes {
display: flex;
text-align: left;
flex-wrap: wrap;
margin-bottom: 8px;
}
#report-boxes i::after {
color: var(--color);
text-shadow: 0 0 48px var(--color);
padding: 16px;
font-size: 28px;
border-radius: 32px;
}
#report-boxes .icon-https::after {
--color: #0C7;
content: "lock";
}
#report-boxes .icon-rocket::after {
--color: #68F;
content: "rocket_launch";
}
#report-boxes .prewarn i::after {
--color: #EA0;
}
#report-boxes .warn i::after {
--color: #F60;
}
#report-boxes .error i::after {
--color: #F22;
}
#report-boxes > div {
display: flex;
width: 50%;
min-width: 256px;
flex: 1;
padding: 20px 8px;
align-items: center;
}
#report-boxes .title {
font-size: 16px;
}
#report-boxes .subtitle {
opacity: .6;
}
.security {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 600px;
padding: 24px;
margin: 120px auto 80px;
text-align: right;
}
.security i {
font-size: 80px;
}
.security #report-score {
font-size: 48px;
}
.security #report {
opacity: .6;
}
.score::after {
content: "%";
font-size: 18px;
}

View File

@ -21,16 +21,16 @@
</div>
<div class="buttons">
<div id="theme-switcher">
<i></i>
<i>&nbsp;</i>
<div class="text">Theme</div>
</div>
<div t="services">
<i>apps</i>
<div class="text">Services</div>
</div>
<div t="settings">
<i>settings</i>
<div class="text">Settings</div>
<div t="more">
<i>more</i>
<div class="text">More</div>
</div>
</div>
</div>
@ -49,7 +49,7 @@
</div>
<!-- More -->
<div class="page" p="settings">
<div class="page" p="more">
<div class="back"><i></i></div>
<div class="wrapper">
<div class="sub-switch" id="switch">

View File

@ -1,7 +1,7 @@
import Drawer from "./UI/Drawer/Drawer"
import Home from "./UI/Home/Home"
import Main from "./UI/Main/Main"
import Settings from "./UI/Settings/Settings"
import More from "./UI/More/More"
import Config from "./Utils/Config"
import { showPage } from "./Utils/DOMUtils"
@ -20,7 +20,7 @@ export default class App {
this.main = new Main()
this.home = new Home()
this.drawer = new Drawer()
this.settings = new Settings()
this.more = new More()
showPage("home")
setTimeout(() => {

View File

@ -1,7 +1,7 @@
import App from "../../App";
export default class Drawer {
constructor(name) {
constructor() {
this.app = new App()
this.config = this.app.config
this.init()

View File

@ -7,11 +7,15 @@ export default class Home {
this.app = new App()
this.config = this.app.config
this.init()
}
init() {
this.initButtons()
this.initHomeUI()
this.initBackButtons()
}
init() {
initButtons() {
let buttons = document.getElementsByClassName("buttons")[0].children
for (let button of buttons) {
let target = button.getAttribute("t")

40
js/UI/More/More.js Normal file
View File

@ -0,0 +1,40 @@
import App from "../../App";
import Privacy from "./Privacy/Privacy";
import Settings from "./Settings/Settings";
export default class More {
constructor() {
this.app = new App()
this.config = this.app.config
this.privacy = new Privacy()
this.settings = new Settings()
this.init()
}
init() {
this.privacy.init()
this.settings.init()
this.initPager()
}
initPager() {
let switcher = document.getElementById("switch")
let buttons = switcher.children
let subsettings = document.getElementById("subsettings")
for (let i = 0; i < buttons.length; i++) {
let button = buttons[i]
subsettings.children[i].setAttribute("style", `--n: ${i}`)
button.addEventListener("click", () => {
let calculatedHeight = subsettings.children[i].offsetHeight
subsettings.style.height = `${calculatedHeight}px`
subsettings.parentNode.setAttribute("style", `--id: ${i}`)
switcher.setAttribute("style", `--switches: ${buttons.length}`)
})
}
buttons[0].click()
}
}

View File

@ -1,74 +1,19 @@
import App from "../../App";
import * as EVENTS from "./events";
import { analyzeService } from "./security";
import * as tiles from "./tiles"
import App from "../../../App";
import { analyzeService } from "./analyzer";
import { privacyBox } from "./tiles";
export default class Settings {
export default class Privacy {
constructor() {
this.app = new App()
this.config = this.app.config
this.init()
}
init() {
this.checkLocalStorage()
this.initSecurityPanel()
this.initSettings()
this.initPager()
this.initPrivacyPanel()
}
initSettings() {
let darkMode = tiles.addOnOffTile(this.config,
"dark_mode", "Dark mode",
"Make the colors more appropriate for low-light environments",
"dark_mode", EVENTS.onThemeChange
)
tiles.addOnOffTile(this.config,
"open_in_new", "Open in new tab",
"Clicking on application will open it in a new browser tab",
"open_new_tab", EVENTS.onNewTabChange
)
tiles.addOnOffTile(this.config,
"blur_on", "Enable blur",
"Improves UI sweetness but may have a huge impact on performance",
"blur", EVENTS.onBlurChange
)
tiles.addOnOffTile(this.config,
"animation", "Animations",
"Show nice and fancy page transitions for improved experience",
"animations", EVENTS.onAnimationChange
)
document.getElementById("theme-switcher").addEventListener("click", () => {
darkMode.click()
})
}
initPager() {
let switcher = document.getElementById("switch")
let buttons = switcher.children
let subsettings = document.getElementById("subsettings")
for (let i = 0; i < buttons.length; i++) {
let button = buttons[i]
subsettings.children[i].setAttribute("style", `--n: ${i}`)
button.addEventListener("click", () => {
let calculatedHeight = subsettings.children[i].offsetHeight
subsettings.style.height = `${calculatedHeight}px`
subsettings.parentNode.setAttribute("style", `--id: ${i}`)
switcher.setAttribute("style", `--switches: ${buttons.length}`)
})
}
buttons[0].click()
}
initSecurityPanel() {
initPrivacyPanel() {
let stats = {
total: 0,
secure: 0,
@ -83,7 +28,8 @@ export default class Settings {
let secure_pp = 100 * stats.secure / stats.total
let indepencence_pp = 100 * (stats.total - stats.thirdParties) / stats.total
let privacy_score = secure_pp * 0.5 + indepencence_pp * 0.5
let https_importance = this.config.get("https_importance")
let privacy_score = secure_pp * https_importance + indepencence_pp * (1 - https_importance)
let privacy_report;
if (privacy_score == 100) {
@ -101,7 +47,7 @@ export default class Settings {
document.getElementById("report").innerText = privacy_report
const phrase = " of the listed services are using secure connections"
tiles.privacyBox(secure_pp, "icon-https", [
privacyBox(secure_pp, "icon-https", [
{
"from": 0,
"name": "No encryption",
@ -129,7 +75,7 @@ export default class Settings {
}
])
tiles.privacyBox(indepencence_pp, "icon-rocket", [
privacyBox(indepencence_pp, "icon-rocket", [
{
"from": 0,
"name": "Not independent",
@ -153,8 +99,4 @@ export default class Settings {
])
}
checkLocalStorage() {
let warn = document.getElementById("no-cookies").classList
if (this.config.storageAvailable) warn.add("hidden")
}
}

View File

@ -0,0 +1,27 @@
export function privacyBox(privacyScore, icon_class, levels) {
let name, desc
levels = levels.reverse()
for (let i in levels) {
let item = levels[i]
if (item.from <= privacyScore) {
name = levels[i].name
desc = levels[i].desc
break
}
}
let item = document.createElement("div")
item.innerHTML = `<i class="${icon_class}"></i>
<div>
<div class="title">${name}</div>
<div class="subtitle">${desc}</div>
</div>`
if (privacyScore < 30) item.classList.add("error")
else if (privacyScore < 90) item.classList.add("warn")
else if (privacyScore < 100) item.classList.add("prewarn")
document.getElementById("report-boxes").appendChild(item)
return item
}

View File

@ -0,0 +1,51 @@
import App from "../../../App";
import { addOnOffTile } from "./tiles";
import * as EVENTS from "./events"
export default class Settings {
constructor() {
this.app = new App()
this.config = this.app.config
}
init() {
this.checkLocalStorage()
this.initSettings()
}
initSettings() {
let darkMode = addOnOffTile(this.config,
"dark_mode", "Dark mode",
"Make the colors more appropriate for low-light environments",
"dark_mode", EVENTS.onThemeChange
)
addOnOffTile(this.config,
"open_in_new", "Open in new tab",
"Clicking on application will open it in a new browser tab",
"open_new_tab", EVENTS.onNewTabChange
)
addOnOffTile(this.config,
"blur_on", "Enable blur",
"Improves UI sweetness but may have a huge impact on performance",
"blur", EVENTS.onBlurChange
)
addOnOffTile(this.config,
"animation", "Animations",
"Show nice and fancy page transitions for improved experience",
"animations", EVENTS.onAnimationChange
)
document.getElementById("theme-switcher").addEventListener("click", () => {
darkMode.click()
})
}
checkLocalStorage() {
let warn = document.getElementById("no-cookies").classList
if (this.config.storageAvailable) warn.add("hidden")
}
}

View File

@ -14,10 +14,12 @@ export function addOnOffTile(conf, icon, name, desc, key, func) {
if (conf.get(key)) c.add("checked")
else c.remove("checked")
}
let write = () => {
let target_value = !conf.get(key)
conf.set(key, target_value)
}
let f = () => {func(conf)}
item.addEventListener("click", write)
@ -29,31 +31,3 @@ export function addOnOffTile(conf, icon, name, desc, key, func) {
document.getElementById("settings").appendChild(item)
return item
}
export function privacyBox(privacyScore, icon_class, levels) {
let name, desc
levels = levels.reverse()
for (let i in levels) {
let item = levels[i]
if (item.from <= privacyScore) {
name = levels[i].name
desc = levels[i].desc
break
}
}
let item = document.createElement("div")
item.innerHTML = `<i class="${icon_class}"></i>
<div>
<div class="title">${name}</div>
<div class="subtitle">${desc}</div>
</div>`
if (privacyScore < 30) item.classList.add("error")
else if (privacyScore < 90) item.classList.add("warn")
else if (privacyScore < 100) item.classList.add("prewarn")
document.getElementById("report-boxes").appendChild(item)
return item
}

View File

@ -8,7 +8,8 @@
"dark_mode": false,
"open_new_tab": false,
"blur": true,
"animations": true
"animations": true,
"https_importance": 0.5
},
"services": [
{