From 55f389a0034a7dafc9038be781863e2fba29bec8 Mon Sep 17 00:00:00 2001 From: amit-077 Date: Fri, 18 Oct 2024 22:05:21 +0530 Subject: [PATCH 1/3] Added dark mode functionality --- index.html | 294 +++++++++-------- index.js | 911 +++++++++++++++++++++++++++++++---------------------- style.css | 75 +++++ 3 files changed, 775 insertions(+), 505 deletions(-) diff --git a/index.html b/index.html index bea9390..954117f 100644 --- a/index.html +++ b/index.html @@ -1,140 +1,170 @@ - - - - - - permission.site - - - - - - - - - -
-
- -
- - HTTP - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - -
- - - - - -
- -

Async Clipboard API

- - - -
- - - -


-

Notes:

- - - - - - - - - - - - - - - - - - - - -
Augmented Reality (AR)Implemented behind the experimental flag chrome://flags/#enable-experimental-web-platform-features.
Encrypted Media (EME)May succeed without permission depending on the implementation.
- Attempts to use known key systems. (See the source for the list of supported key systems.) - -
Async Clipboard - These buttons test the new Async Clipboard API. -
- Note that these tests are different from the "Copy" button on this page, which uses the old - (synchronous) execCommand method to write to the clipboard. -
- This feature is implemented behind the experimental flag chrome://flags/#enable-experimental-web-platform-features. -
- To enable the Content Settings UX for setting clipboard permission, you'll also need to enable - chrome://flags/#clipboard-content-setting -
- Note: Only available for secure connections (https). -
WebAuthn Attestation - After pressing the button, you may need to touch your security key before you can see an attestation prompt. -
Device Orientation/Motion - May succeed without permission request depending on the implementation. -
- -
-
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + +
+ + + + + + +
+ +

Async Clipboard API

+ + + +
+ + + +


+

Notes:

+ + + + + + + + + + + + + + + + + + + + + +
Augmented Reality (AR) + Implemented behind the experimental flag + chrome://flags/#enable-experimental-web-platform-features. +
Encrypted Media (EME) + May succeed without permission depending on the implementation.
+ Attempts to use known key systems. (See the source for the list of + supported key systems.) + +
Async Clipboard + These buttons test the new + Async Clipboard API. +
+ Note that these tests are different from the "Copy" button on this + page, which uses the old (synchronous) + execCommand method to write to the clipboard. +
+ This feature is implemented behind the experimental flag + chrome://flags/#enable-experimental-web-platform-features. +
+ To enable the Content Settings UX for setting clipboard permission, + you'll also need to enable + chrome://flags/#clipboard-content-setting +
+ Note: Only available for secure connections (https). +
WebAuthn Attestation + After pressing the button, you may need to touch your security key + before you can see an attestation prompt. +
Device Orientation/Motion + May succeed without permission request depending on the + implementation. +
+
+
-
-
+
+
-
- - - + + diff --git a/index.js b/index.js index 674692e..fd65107 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,39 @@ - // - Information about clearing settings in Chrome (can't link to chrome:// URLs) // - Indicate if permissions are already granted, if the relevant API allows it. -window.addEventListener("load", function() { +let mode = "light"; + +function toggleMode() { + if (mode === "light") { + document.body.style.backgroundColor = "#333"; + const buttons = document.querySelectorAll("button"); + buttons.forEach((button) => { + button.style.backgroundColor = "#666"; + button.style.color = "#f1f1f1"; + }); + document.getElementsByClassName("https")[0].style.color = "#f5f5f5"; + document.getElementsByClassName("AsyncClipAPI")[0].style.color = "#f5f5f5"; + document.getElementsByClassName("notes")[0].style.color = "#f5f5f5"; + document.getElementById("tableNotes").style.color = "#fff"; + document.getElementById("darkModeText").style.color = "#fff"; + mode = "dark"; + } else { + document.body.style.backgroundColor = "#EEE"; + const buttons = document.querySelectorAll("button"); + buttons.forEach((button) => { + button.style.backgroundColor = "#fff"; + button.style.color = "#000"; + }); + document.getElementsByClassName("https")[0].style.color = "#666"; + document.getElementsByClassName("AsyncClipAPI")[0].style.color = "#000"; + document.getElementsByClassName("notes")[0].style.color = "#000"; + document.getElementById("tableNotes").style.color = "#000"; + document.getElementById("darkModeText").style.color = "#000"; + mode = "light"; + } +} +window.addEventListener("load", function () { var toggle = document.querySelector("#toggle"); toggle.classList.add("instant"); if (window.location.protocol == "https:") { @@ -13,14 +43,14 @@ window.addEventListener("load", function() { toggle.classList.add("http"); toggle.protocol = "https:"; } - setTimeout(function() { + setTimeout(function () { toggle.classList.remove("instant"); }, 10); function displayOutcome(type, outcome) { - return function() { + return function () { var argList = [outcome, type].concat([].slice.call(arguments)); - switch(outcome) { + switch (outcome) { case "success": console.info.apply(console, argList); break; @@ -30,13 +60,15 @@ window.addEventListener("load", function() { default: console.log.apply(console, argList); } - document.getElementById(type).classList.remove('success', 'error', 'default'); + document + .getElementById(type) + .classList.remove("success", "error", "default"); document.getElementById(type).classList.add(outcome); }; - }; + } function displayOutcomeForNotifications(outcome) { - switch(outcome) { + switch (outcome) { case "granted": console.info(outcome, "notifications"); document.getElementById("notifications").classList.add("success"); @@ -51,66 +83,65 @@ window.addEventListener("load", function() { default: throw "Unknown notification API response."; } - }; + } function triggerDownload() { // Based on http://stackoverflow.com/a/27280611 - var a = document.createElement('a'); + var a = document.createElement("a"); a.download = "test-image.png"; - a.href = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABC0lEQVQYlTXPPUsCYQDA8b/e04tdQR5ZBpE3NAR6S0SDVDZKDQ2BY9TUy1foE0TQ1Edo6hOEkyUG0QuBRtQgl0hnenVdnZD5eLbU7xv8Avy5X16KhrQBg47EtpziXO6qBhAEeNEm0qr7VdBcLxt2mlnNbhVu0NMAgdj1wvjOoX2xdSt0L7MGgx2GGid8yLrJvJMUkbKfOF8N68bUIqcz2wQR7GUcYvJIr1dFQijvkh89xGV6BPPMwvMF/nQXJMgWiM+KLPX2tc0HNa/HUxDv2owpx7xV+023Hiwpdt7yhmcjj9/NdrIhn8LrPVmotctWVd01Nt27wH9T3YhHU5O+sT/6SuVZKa4cNGoAv/ZMas7pC/KaAAAAAElFTkSuQmCC"; + a.href = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAABC0lEQVQYlTXPPUsCYQDA8b/e04tdQR5ZBpE3NAR6S0SDVDZKDQ2BY9TUy1foE0TQ1Edo6hOEkyUG0QuBRtQgl0hnenVdnZD5eLbU7xv8Avy5X16KhrQBg47EtpziXO6qBhAEeNEm0qr7VdBcLxt2mlnNbhVu0NMAgdj1wvjOoX2xdSt0L7MGgx2GGid8yLrJvJMUkbKfOF8N68bUIqcz2wQR7GUcYvJIr1dFQijvkh89xGV6BPPMwvMF/nQXJMgWiM+KLPX2tc0HNa/HUxDv2owpx7xV+023Hiwpdt7yhmcjj9/NdrIhn8LrPVmotctWVd01Nt27wH9T3YhHU5O+sT/6SuVZKa4cNGoAv/ZMas7pC/KaAAAAAElFTkSuQmCC"; a.click(); } function isFullscreen() { - return document.fullscreenElement || - document.webkitFullscreenElement || - document.mozFullScreenElement || - document.msFullscreenElement; + return ( + document.fullscreenElement || + document.webkitFullscreenElement || + document.mozFullScreenElement || + document.msFullscreenElement + ); } function isPointerLocked() { - return document.pointerLockElement || - document.webkitPointerLockElement || - document.mozPointerLockElement || - document.msPointerLockElement; + return ( + document.pointerLockElement || + document.webkitPointerLockElement || + document.mozPointerLockElement || + document.msPointerLockElement + ); } - navigator.getUserMedia = ( + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || - navigator.msGetUserMedia - ); - navigator.requestMIDIAccess = ( + navigator.msGetUserMedia; + navigator.requestMIDIAccess = navigator.requestMIDIAccess || navigator.webkitRequestMIDIAccess || navigator.mozRequestMIDIAccess || - navigator.msRequestMIDIAccess - ); - document.documentElement.requestFullscreen = ( + navigator.msRequestMIDIAccess; + document.documentElement.requestFullscreen = document.documentElement.requestFullscreen || document.documentElement.webkitRequestFullscreen || document.documentElement.mozRequestFullscreen || - document.documentElement.msRequestFullscreen - ); - document.exitFullscreen = ( + document.documentElement.msRequestFullscreen; + document.exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || - document.msExitFullscreen - ); - document.body.requestPointerLock = ( + document.msExitFullscreen; + document.body.requestPointerLock = document.body.requestPointerLock || document.body.webkitRequestPointerLock || document.body.mozRequestPointerLock || - document.body.msRequestPointerLock - ); - document.exitPointerLock = ( + document.body.msRequestPointerLock; + document.exitPointerLock = document.exitPointerLock || document.webkitExitPointerLock || document.mozExitPointerLock || - document.msExitPointerLock - ); + document.msExitPointerLock; document.addEventListener("fullscreenchange", (e) => { displayOutcome("fullscreen", isFullscreen() ? "success" : "default")(e); @@ -126,137 +157,148 @@ window.addEventListener("load", function() { }); var register = { - "notifications": function () { - Notification.requestPermission( - displayOutcomeForNotifications - ); + notifications: function () { + Notification.requestPermission(displayOutcomeForNotifications); }, - "location": function() { + location: function () { navigator.geolocation.getCurrentPosition( displayOutcome("location", "success"), displayOutcome("location", "error") ); }, - "camera": function() { - navigator.mediaDevices ? - navigator.mediaDevices.getUserMedia( - {video: true}).then( + camera: function () { + navigator.mediaDevices + ? navigator.mediaDevices + .getUserMedia({ video: true }) + .then( + displayOutcome("camera", "success"), + displayOutcome("camera", "error") + ) + : navigator.getUserMedia( + { video: true }, displayOutcome("camera", "success"), displayOutcome("camera", "error") - ) : - navigator.getUserMedia( - {video: true}, - displayOutcome("camera", "success"), - displayOutcome("camera", "error") - ); + ); }, - "microphone": function() { - navigator.mediaDevices ? - navigator.mediaDevices.getUserMedia( - {audio: true}).then( + microphone: function () { + navigator.mediaDevices + ? navigator.mediaDevices + .getUserMedia({ audio: true }) + .then( + displayOutcome("microphone", "success"), + displayOutcome("microphone", "error") + ) + : navigator.getUserMedia( + { audio: true }, displayOutcome("microphone", "success"), displayOutcome("microphone", "error") - ) : - navigator.getUserMedia( - {audio: true}, - displayOutcome("microphone", "success"), - displayOutcome("microphone", "error") - ); + ); }, - "camera+microphone": function() { - navigator.mediaDevices ? - navigator.mediaDevices.getUserMedia( - {audio: true, video: true}).then( + "camera+microphone": function () { + navigator.mediaDevices + ? navigator.mediaDevices + .getUserMedia({ audio: true, video: true }) + .then( + displayOutcome("camera+microphone", "success"), + displayOutcome("camera+microphone", "error") + ) + : navigator.getUserMedia( + { audio: true, video: true }, displayOutcome("camera+microphone", "success"), displayOutcome("camera+microphone", "error") - ) : - navigator.getUserMedia( - {audio: true, video: true}, - displayOutcome("camera+microphone", "success"), - displayOutcome("camera+microphone", "error") - ); + ); }, - "pan-tilt-zoom": function() { - navigator.mediaDevices ? - navigator.mediaDevices.getUserMedia( - {video: {pan: true, tilt: true, zoom: true}}).then( + "pan-tilt-zoom": function () { + navigator.mediaDevices + ? navigator.mediaDevices + .getUserMedia({ video: { pan: true, tilt: true, zoom: true } }) + .then( + displayOutcome("pan-tilt-zoom", "success"), + displayOutcome("pan-tilt-zoom", "error") + ) + : navigator.getUserMedia( + { video: { pan: true, tilt: true, zoom: true } }, displayOutcome("pan-tilt-zoom", "success"), displayOutcome("pan-tilt-zoom", "error") - ) : - navigator.getUserMedia( - {video: {pan: true, tilt: true, zoom: true}}, - displayOutcome("pan-tilt-zoom", "success"), - displayOutcome("pan-tilt-zoom", "error") - ); + ); }, - "pan-tilt-zoom+microphone": function() { - navigator.mediaDevices ? - navigator.mediaDevices.getUserMedia( - {video: {pan: true, tilt: true, zoom: true}, audio: true}).then( + "pan-tilt-zoom+microphone": function () { + navigator.mediaDevices + ? navigator.mediaDevices + .getUserMedia({ + video: { pan: true, tilt: true, zoom: true }, + audio: true, + }) + .then( + displayOutcome("pan-tilt-zoom+microphone", "success"), + displayOutcome("pan-tilt-zoom+microphone", "error") + ) + : navigator.getUserMedia( + { video: { pan: true, tilt: true, zoom: true }, audio: true }, displayOutcome("pan-tilt-zoom+microphone", "success"), displayOutcome("pan-tilt-zoom+microphone", "error") - ) : - navigator.getUserMedia( - {video: {pan: true, tilt: true, zoom: true}, audio: true}, - displayOutcome("pan-tilt-zoom+microphone", "success"), - displayOutcome("pan-tilt-zoom+microphone", "error") - ); - }, - "screenshare": function() { - navigator.mediaDevices.getDisplayMedia().then( - displayOutcome("screenshare", "success"), - displayOutcome("screenshare", "error") - ); + ); }, - "midi": function() { - navigator.requestMIDIAccess({ - sysex: false - }).then( - displayOutcome("midi", "success"), - displayOutcome("midi", "error") - ); + screenshare: function () { + navigator.mediaDevices + .getDisplayMedia() + .then( + displayOutcome("screenshare", "success"), + displayOutcome("screenshare", "error") + ); }, - "midi+sysex": function() { - navigator.requestMIDIAccess({ - sysex: true - }).then( - displayOutcome("midi+sysex", "success"), - displayOutcome("midi+sysex", "error") - ); + midi: function () { + navigator + .requestMIDIAccess({ + sysex: false, + }) + .then( + displayOutcome("midi", "success"), + displayOutcome("midi", "error") + ); }, - "bluetooth": function() { - navigator.bluetooth.requestDevice({ - // filters: [...] <- Prefer filters to save energy & show relevant devices. - // acceptAllDevices here ensures dialog can populate, we don't care with what. - acceptAllDevices:true - }) - .then(device => device.gatt.connect()) - .then( - displayOutcome("bluetooth", "success"), - displayOutcome("bluetooth", "error") - ); + "midi+sysex": function () { + navigator + .requestMIDIAccess({ + sysex: true, + }) + .then( + displayOutcome("midi+sysex", "success"), + displayOutcome("midi+sysex", "error") + ); }, - "usb": function() { - navigator.usb.requestDevice({filters: [{}]}).then( - displayOutcome("usb", "success"), - displayOutcome("usb", "error") - ); + bluetooth: function () { + navigator.bluetooth + .requestDevice({ + // filters: [...] <- Prefer filters to save energy & show relevant devices. + // acceptAllDevices here ensures dialog can populate, we don't care with what. + acceptAllDevices: true, + }) + .then((device) => device.gatt.connect()) + .then( + displayOutcome("bluetooth", "success"), + displayOutcome("bluetooth", "error") + ); }, - "serial": function() { - navigator.serial.requestPort({filters: []}).then( - displayOutcome("serial", "success"), - displayOutcome("serial", "error") - ); + usb: function () { + navigator.usb + .requestDevice({ filters: [{}] }) + .then(displayOutcome("usb", "success"), displayOutcome("usb", "error")); + }, + serial: function () { + navigator.serial + .requestPort({ filters: [] }) + .then( + displayOutcome("serial", "success"), + displayOutcome("serial", "error") + ); }, - "hid": function() { - navigator.hid.requestDevice({filters: []}).then( - devices => { - displayOutcome("hid", devices.length > 0 ? "success" : "error")(); - }, - displayOutcome("hid", "error") - ); + hid: function () { + navigator.hid.requestDevice({ filters: [] }).then((devices) => { + displayOutcome("hid", devices.length > 0 ? "success" : "error")(); + }, displayOutcome("hid", "error")); }, - "eme": function() { + eme: function () { // https://w3c.github.io/encrypted-media/#requestMediaKeySystemAccess // Tries multiple configuration per key system. The configurations are in // descending order of privileges such that a supported permission-requiring @@ -264,16 +306,16 @@ window.addEventListener("load", function() { // require permissions. var knownKeySystems = [ - "com.example.somesystem", // Ensure no real system is the first tried. + "com.example.somesystem", // Ensure no real system is the first tried. "com.widevine.alpha", "com.microsoft.playready", "com.adobe.primetime", "com.apple.fps.2_0", "com.apple.fps", "com.apple.fps.1_0", - "com.example.somesystem" // Ensure no real system is the last tried. + "com.example.somesystem", // Ensure no real system is the last tried. ]; - var tryKeySystem = function(keySystem) { + var tryKeySystem = function (keySystem) { // http://w3c.github.io/encrypted-media/#idl-def-mediakeysystemconfiguration // One of videoCapabilities or audioCapabilities must be present. Pick // a set that all browsers should support at least one of. @@ -281,43 +323,48 @@ window.addEventListener("load", function() { { contentType: 'audio/mp4; codecs="mp4a.40.2"' }, { contentType: 'audio/webm; codecs="opus"' }, ]; - navigator.requestMediaKeySystemAccess( - keySystem, - [ - { distinctiveIdentifier: "required", + navigator + .requestMediaKeySystemAccess(keySystem, [ + { + distinctiveIdentifier: "required", persistentState: "required", audioCapabilities: capabilities, - label: "'distinctiveIdentifier' and 'persistentState' required" + label: "'distinctiveIdentifier' and 'persistentState' required", }, - { distinctiveIdentifier: "required", + { + distinctiveIdentifier: "required", audioCapabilities: capabilities, - label: "'distinctiveIdentifier' required" + label: "'distinctiveIdentifier' required", }, - { persistentState: "required", + { + persistentState: "required", audioCapabilities: capabilities, - label: "'persistentState' required" + label: "'persistentState' required", }, - { audioCapabilities: capabilities, - label: "empty" + { audioCapabilities: capabilities, label: "empty" }, + { label: "no capabilities" }, + ]) + .then( + function (mediaKeySystemAccess) { + displayOutcome("eme", "success")( + "Key System: " + keySystem, + "Configuration: " + + mediaKeySystemAccess.getConfiguration().label, + mediaKeySystemAccess + ); }, - { label: "no capabilities" } - ] - ).then( - function (mediaKeySystemAccess) { - displayOutcome("eme", "success")( - "Key System: " + keySystem, - "Configuration: " + mediaKeySystemAccess.getConfiguration().label, - mediaKeySystemAccess); - }, - function (error) { - if (knownKeySystems.length > 0) - return tryKeySystem(knownKeySystems.shift()); - - displayOutcome("eme", "error")( - error, - error.name == "NotSupportedError" ? "No known key systems supported or permitted." : ""); - } - ); + function (error) { + if (knownKeySystems.length > 0) + return tryKeySystem(knownKeySystems.shift()); + + displayOutcome("eme", "error")( + error, + error.name == "NotSupportedError" + ? "No known key systems supported or permitted." + : "" + ); + } + ); }; tryKeySystem(knownKeySystems.shift()); }, @@ -335,89 +382,102 @@ window.addEventListener("load", function() { try { const status = await IdleDetector.requestPermission(); if (status != "granted") { - displayOutcome("idle-detection", "error")(`Permission status: ${status}`); + displayOutcome( + "idle-detection", + "error" + )(`Permission status: ${status}`); return; } controller = new AbortController(); const detector = new IdleDetector(); - detector.addEventListener('change', () => { - console.log(`Idle change: ${detector.userState}, ${detector.screenState}.`); + detector.addEventListener("change", () => { + console.log( + `Idle change: ${detector.userState}, ${detector.screenState}.` + ); }); - await detector.start({signal: controller.signal}); + await detector.start({ signal: controller.signal }); displayOutcome("idle-detection", "success")(); } catch (e) { controller = null; displayOutcome("idle-detection", "error")(e); } }; - }()), - "copy": (function() { + })(), + copy: (function () { var interceptCopy = false; - document.addEventListener("copy", function(e){ + document.addEventListener("copy", function (e) { if (interceptCopy) { // From http://www.w3.org/TR/clipboard-apis/#h4_the-copy-action - e.clipboardData.setData("text/plain", + e.clipboardData.setData( + "text/plain", "This text was copied from the permission.site clipboard example." ); - e.clipboardData.setData("text/html", + e.clipboardData.setData( + "text/html", "This text was copied from the " + - "" + - "permission.site clipboard example." + "" + + "permission.site clipboard example." ); e.preventDefault(); } }); - return function() { + return function () { interceptCopy = true; document.execCommand("copy"); interceptCopy = false; }; - }()), - "popup": function() { + })(), + popup: function () { var w = window.open( location.href, "Popup", "resizable,scrollbars,status" - ) + ); displayOutcome("popup", w ? "success" : "error")(w); }, - "popup-delayed": function() { - setTimeout(function() { + "popup-delayed": function () { + setTimeout(function () { var w = window.open( location.href, "Popup", "resizable,scrollbars,status" - ) + ); displayOutcome("popup-delayed", w ? "success" : "error")(w); }, 5000); }, - "fullscreen": function() { + fullscreen: function () { try { if (!isFullscreen()) { - document.documentElement.requestFullscreen().then( - displayOutcome("fullscreen", "success")("enter"), - displayOutcome("fullscreen", "error") - ); + document.documentElement + .requestFullscreen() + .then( + displayOutcome("fullscreen", "success")("enter"), + displayOutcome("fullscreen", "error") + ); } else { - document.exitFullscreen().then( - displayOutcome("fullscreen", "default")("exit"), - displayOutcome("fullscreen", "error") - ); + document + .exitFullscreen() + .then( + displayOutcome("fullscreen", "default")("exit"), + displayOutcome("fullscreen", "error") + ); } } catch (e) { displayOutcome("fullscreen", "error")(e); } }, - "pointerlock": function() { + pointerlock: function () { try { if (!window.pointerLocked) { - document.body.requestPointerLock().then( - displayOutcome("pointerlock", "success")("locked"), - displayOutcome("pointerlock", "error") - ); + document.body + .requestPointerLock() + .then( + displayOutcome("pointerlock", "success")("locked"), + displayOutcome("pointerlock", "error") + ); } else { document.exitPointerLock(); displayOutcome("pointerlock", "default")("unlocked"); @@ -426,15 +486,20 @@ window.addEventListener("load", function() { displayOutcome("pointerlock", "error")(e); } }, - "keyboardlock": function() { + keyboardlock: function () { try { if (!window.keyboardLockRequested) { window.keyboardLockRequested = true; // Note: As of 2023-12-14, Chrome resolves the promise immediately and holds the lock in a pending state when the document is not fullscreen. - navigator.keyboard.lock().then( - displayOutcome("keyboardlock", "success")(isFullscreen() ? "locked" : "will lock in fullscreen"), - displayOutcome("keyboardlock", "error") - ); + navigator.keyboard + .lock() + .then( + displayOutcome( + "keyboardlock", + "success" + )(isFullscreen() ? "locked" : "will lock in fullscreen"), + displayOutcome("keyboardlock", "error") + ); } else { window.keyboardLockRequested = false; navigator.keyboard.unlock(); @@ -444,219 +509,302 @@ window.addEventListener("load", function() { displayOutcome("keyboardlock", "error")(e); } }, - "download": function() { + download: function () { // Two downloads at the same time trigger a permission prompt in Chrome. triggerDownload(); triggerDownload(); }, - "keygen": function() { + keygen: function () { var keygen = document.createElement("keygen"); document.getElementById("keygen-container").appendChild(keygen); }, - "persistent-storage": function() { + "persistent-storage": function () { // https://storage.spec.whatwg.org - navigator.storage.persist().then( - function(persisted) { - displayOutcome("persistent-storage", persisted ? "success" : "default")(persisted); - }, - displayOutcome("persistent-storage", "error") - ) + navigator.storage.persist().then(function (persisted) { + displayOutcome( + "persistent-storage", + persisted ? "success" : "default" + )(persisted); + }, displayOutcome("persistent-storage", "error")); }, - - "protocol-handler": function() { + + "protocol-handler": function () { // https://www.w3.org/TR/html5/webappapis.html#navigatorcontentutils - var url = window.location + '%s'; + var url = window.location + "%s"; try { - navigator.registerProtocolHandler('web+permissionsite', url, 'title'); - } catch(e) { + navigator.registerProtocolHandler("web+permissionsite", url, "title"); + } catch (e) { displayOutcome("protocol-handler", "error")(e); } }, - "read-text": function() { + "read-text": function () { var cb = navigator.clipboard; if (cb) { - cb.readText().then(function(data) { - displayOutcome("read-text", "success")("Successfully read data from clipboard: '" + data + "'"); - }, function() { - displayOutcome("read-text", "error")("Failed to read from clipboard"); - }); + cb.readText().then( + function (data) { + displayOutcome( + "read-text", + "success" + )("Successfully read data from clipboard: '" + data + "'"); + }, + function () { + displayOutcome( + "read-text", + "error" + )("Failed to read from clipboard"); + } + ); } else { - displayOutcome("read-text", "error")("navigator.clipboard not available"); + displayOutcome( + "read-text", + "error" + )("navigator.clipboard not available"); } }, - "write-text": function() { + "write-text": function () { var cb = navigator.clipboard; if (cb) { - navigator.clipboard.writeText("new clipboard data").then(function() { - displayOutcome("write-text", "success")("Successfully wrote data to clipboard"); - }, function() { - displayOutcome("write-text", "error")("Failed to write to clipboard"); - }); + navigator.clipboard.writeText("new clipboard data").then( + function () { + displayOutcome( + "write-text", + "success" + )("Successfully wrote data to clipboard"); + }, + function () { + displayOutcome( + "write-text", + "error" + )("Failed to write to clipboard"); + } + ); } else { - displayOutcome("write-text", "error")("navigator.clipboard not available"); + displayOutcome( + "write-text", + "error" + )("navigator.clipboard not available"); } }, - "read-text-delayed": function() { + "read-text-delayed": function () { var cb = navigator.clipboard; if (cb) { - setTimeout(function() { - navigator.clipboard.readText().then(function(data) { - displayOutcome("read-text-delayed", "success")("Successfully read data from clipboard: '" + data + "'"); - }, function() { - displayOutcome("read-text-delayed", "error")("Failed to read from clipboard"); - }); + setTimeout(function () { + navigator.clipboard.readText().then( + function (data) { + displayOutcome( + "read-text-delayed", + "success" + )("Successfully read data from clipboard: '" + data + "'"); + }, + function () { + displayOutcome( + "read-text-delayed", + "error" + )("Failed to read from clipboard"); + } + ); }, 5000); } else { - displayOutcome("read-text-delayed", "error")("navigator.clipboard not available"); + displayOutcome( + "read-text-delayed", + "error" + )("navigator.clipboard not available"); } }, - "write-text-delayed": function() { + "write-text-delayed": function () { var cb = navigator.clipboard; if (cb) { - setTimeout(function() { - navigator.clipboard.writeText("new (delayed) clipboard data").then(function() { - displayOutcome("write-text-delayed", "success")("Successfully wrote data to clipboard"); - }, function() { - displayOutcome("write-text-delayed", "error")("Failed to write to clipboard"); - }); + setTimeout(function () { + navigator.clipboard.writeText("new (delayed) clipboard data").then( + function () { + displayOutcome( + "write-text-delayed", + "success" + )("Successfully wrote data to clipboard"); + }, + function () { + displayOutcome( + "write-text-delayed", + "error" + )("Failed to write to clipboard"); + } + ); }, 5000); } else { - displayOutcome("write-text-delayed", "error")("navigator.clipboard not available"); + displayOutcome( + "write-text-delayed", + "error" + )("navigator.clipboard not available"); } }, - "webauthn-attestation": function() { + "webauthn-attestation": function () { // From https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API // This code is public domain, per https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses // sample arguments for registration var createCredentialDefaultArgs = { - publicKey: { - // Relying Party (a.k.a. - Service): - rp: { - name: "Acme" - }, - - // User: - user: { - id: new Uint8Array(16), - name: "john.p.smith@example.com", - displayName: "John P. Smith" - }, - - pubKeyCredParams: [{ - type: "public-key", - alg: -7 - }], - - attestation: "direct", - - timeout: 60000, - - challenge: new Uint8Array([ // must be a cryptographically random number sent from a server - 0x8C, 0x0A, 0x26, 0xFF, 0x22, 0x91, 0xC1, 0xE9, 0xB9, 0x4E, 0x2E, 0x17, 0x1A, 0x98, 0x6A, 0x73, - 0x71, 0x9D, 0x43, 0x48, 0xD5, 0xA7, 0x6A, 0x15, 0x7E, 0x38, 0x94, 0x52, 0x77, 0x97, 0x0F, 0xEF - ]).buffer - } + publicKey: { + // Relying Party (a.k.a. - Service): + rp: { + name: "Acme", + }, + + // User: + user: { + id: new Uint8Array(16), + name: "john.p.smith@example.com", + displayName: "John P. Smith", + }, + + pubKeyCredParams: [ + { + type: "public-key", + alg: -7, + }, + ], + + attestation: "direct", + + timeout: 60000, + + challenge: new Uint8Array([ + // must be a cryptographically random number sent from a server + 0x8c, 0x0a, 0x26, 0xff, 0x22, 0x91, 0xc1, 0xe9, 0xb9, 0x4e, 0x2e, + 0x17, 0x1a, 0x98, 0x6a, 0x73, 0x71, 0x9d, 0x43, 0x48, 0xd5, 0xa7, + 0x6a, 0x15, 0x7e, 0x38, 0x94, 0x52, 0x77, 0x97, 0x0f, 0xef, + ]).buffer, + }, }; // sample arguments for login var getCredentialDefaultArgs = { - publicKey: { - timeout: 60000, - // allowCredentials: [newCredential] // see below - challenge: new Uint8Array([ // must be a cryptographically random number sent from a server - 0x79, 0x50, 0x68, 0x71, 0xDA, 0xEE, 0xEE, 0xB9, 0x94, 0xC3, 0xC2, 0x15, 0x67, 0x65, 0x26, 0x22, - 0xE3, 0xF3, 0xAB, 0x3B, 0x78, 0x2E, 0xD5, 0x6F, 0x81, 0x26, 0xE2, 0xA6, 0x01, 0x7D, 0x74, 0x50 - ]).buffer - }, + publicKey: { + timeout: 60000, + // allowCredentials: [newCredential] // see below + challenge: new Uint8Array([ + // must be a cryptographically random number sent from a server + 0x79, 0x50, 0x68, 0x71, 0xda, 0xee, 0xee, 0xb9, 0x94, 0xc3, 0xc2, + 0x15, 0x67, 0x65, 0x26, 0x22, 0xe3, 0xf3, 0xab, 0x3b, 0x78, 0x2e, + 0xd5, 0x6f, 0x81, 0x26, 0xe2, 0xa6, 0x01, 0x7d, 0x74, 0x50, + ]).buffer, + }, }; // register / create a new credential - navigator.credentials.create(createCredentialDefaultArgs) - .then((cred) => { - console.log("NEW CREDENTIAL", cred); - - // normally the credential IDs available for an account would come from a server - // but we can just copy them from above... - var idList = [{ - id: cred.rawId, - transports: ["usb", "nfc", "ble"], - type: "public-key" - }]; - getCredentialDefaultArgs.publicKey.allowCredentials = idList; - return navigator.credentials.get(getCredentialDefaultArgs); - }) - .then((assertion) => { - displayOutcome("webauthn-attestation", "success")(assertion); - }) - .catch((err) => { - displayOutcome("webauthn-attestation", "error")(err); - }); - }, - "nfc": function() { - if ('NDEFReader' in window) { - const reader = new NDEFReader(); - reader.scan() - .then(() => { - displayOutcome("nfc", "success")("Successfully started NFC scan"); + navigator.credentials + .create(createCredentialDefaultArgs) + .then((cred) => { + console.log("NEW CREDENTIAL", cred); + + // normally the credential IDs available for an account would come from a server + // but we can just copy them from above... + var idList = [ + { + id: cred.rawId, + transports: ["usb", "nfc", "ble"], + type: "public-key", + }, + ]; + getCredentialDefaultArgs.publicKey.allowCredentials = idList; + return navigator.credentials.get(getCredentialDefaultArgs); + }) + .then((assertion) => { + displayOutcome("webauthn-attestation", "success")(assertion); }) .catch((err) => { - displayOutcome("nfc", "error")(err); + displayOutcome("webauthn-attestation", "error")(err); }); + }, + nfc: function () { + if ("NDEFReader" in window) { + const reader = new NDEFReader(); + reader + .scan() + .then(() => { + displayOutcome("nfc", "success")("Successfully started NFC scan"); + }) + .catch((err) => { + displayOutcome("nfc", "error")(err); + }); } else { displayOutcome("nfc", "error")("NDEFReader is not available"); } }, - "vr": function() { - if ('xr' in navigator) { - navigator.xr.requestSession('immersive-vr') - .then(() => { - displayOutcome("vr", "success")("Successfully entered VR"); - }) - .catch((err) => { - displayOutcome("vr", "error")(err); - }); + vr: function () { + if ("xr" in navigator) { + navigator.xr + .requestSession("immersive-vr") + .then(() => { + displayOutcome("vr", "success")("Successfully entered VR"); + }) + .catch((err) => { + displayOutcome("vr", "error")(err); + }); } else { displayOutcome("vr", "error")("navigator.xr is not available"); } }, - "ar": function() { - if ('xr' in navigator) { - navigator.xr.requestSession('immersive-ar') - .then(() => { - displayOutcome("ar", "success")("Successfully entered AR"); - }) - .catch((err) => { - displayOutcome("ar", "error")(err); - }); + ar: function () { + if ("xr" in navigator) { + navigator.xr + .requestSession("immersive-ar") + .then(() => { + displayOutcome("ar", "success")("Successfully entered AR"); + }) + .catch((err) => { + displayOutcome("ar", "error")(err); + }); } else { displayOutcome("ar", "error")("navigator.xr is not available"); } }, - "orientation": function() { + orientation: function () { if ("ondeviceorientation" in window) { - const handleDeviceOrientation = () => window.addEventListener("deviceorientation", (event) => { - if (event.alpha === null && event.beta === null && event.gamma === null) { - displayOutcome("orientation", "error")("Device has no the required sensors"); - } else { - displayOutcome("orientation", "success")("Device has the required sensors"); - } - }, { once: true }); + const handleDeviceOrientation = () => + window.addEventListener( + "deviceorientation", + (event) => { + if ( + event.alpha === null && + event.beta === null && + event.gamma === null + ) { + displayOutcome( + "orientation", + "error" + )("Device has no the required sensors"); + } else { + displayOutcome( + "orientation", + "success" + )("Device has the required sensors"); + } + }, + { once: true } + ); - if (window.DeviceOrientationEvent && window.DeviceOrientationEvent.requestPermission) { + if ( + window.DeviceOrientationEvent && + window.DeviceOrientationEvent.requestPermission + ) { window.DeviceOrientationEvent.requestPermission() .then((permissionState) => { - console.log(`Device Orientation permission state: ${permissionState}`); + console.log( + `Device Orientation permission state: ${permissionState}` + ); if (permissionState !== "granted") { // If permission prompt is ignored or dismissed, // the permission state value is `default`, and permission can be requested again. // https://w3c.github.io/deviceorientation/#id=permission-model - displayOutcome("orientation", "error")(`Device Orientation permission state: ${permissionState}`); + displayOutcome( + "orientation", + "error" + )(`Device Orientation permission state: ${permissionState}`); } else { handleDeviceOrientation(); } @@ -669,30 +817,47 @@ window.addEventListener("load", function() { handleDeviceOrientation(); } } else { - displayOutcome("orientation", "error")("Device Orientation is not supported"); + displayOutcome( + "orientation", + "error" + )("Device Orientation is not supported"); } }, - "motion": function() { + motion: function () { if ("ondevicemotion" in window) { - const handleDeviceMotion = () => window.addEventListener("devicemotion", (event) => { - if ( - event.acceleration.x === null && - event.acceleration.y === null && - event.acceleration.z === null && - event.accelerationIncludingGravity.x === null && - event.accelerationIncludingGravity.y === null && - event.accelerationIncludingGravity.z === null && - event.rotationRate.alpha === null && - event.rotationRate.beta === null && - event.rotationRate.gamma === null - ) { - displayOutcome("motion", "error")("Device has no the required sensors"); - } else { - displayOutcome("motion", "success")("Device has the required sensors"); - } - }, { once: true }); + const handleDeviceMotion = () => + window.addEventListener( + "devicemotion", + (event) => { + if ( + event.acceleration.x === null && + event.acceleration.y === null && + event.acceleration.z === null && + event.accelerationIncludingGravity.x === null && + event.accelerationIncludingGravity.y === null && + event.accelerationIncludingGravity.z === null && + event.rotationRate.alpha === null && + event.rotationRate.beta === null && + event.rotationRate.gamma === null + ) { + displayOutcome( + "motion", + "error" + )("Device has no the required sensors"); + } else { + displayOutcome( + "motion", + "success" + )("Device has the required sensors"); + } + }, + { once: true } + ); - if (window.DeviceMotionEvent && window.DeviceMotionEvent.requestPermission) { + if ( + window.DeviceMotionEvent && + window.DeviceMotionEvent.requestPermission + ) { window.DeviceMotionEvent.requestPermission() .then((permissionState) => { console.log(`Device Motion permission state: ${permissionState}`); @@ -700,7 +865,10 @@ window.addEventListener("load", function() { // If permission prompt is ignored or dismissed, // the permission state value is `default`, and permission can be requested again. // https://w3c.github.io/deviceorientation/#id=permission-model - displayOutcome("motion", "error")(`Device Motion permission state: ${permissionState}`); + displayOutcome( + "motion", + "error" + )(`Device Motion permission state: ${permissionState}`); } else { handleDeviceMotion(); } @@ -715,13 +883,10 @@ window.addEventListener("load", function() { } else { displayOutcome("motion", "error")("Device Motion is not supported"); } - } + }, }; for (var type in register) { - document.getElementById(type).addEventListener('click', - register[type] - ); + document.getElementById(type).addEventListener("click", register[type]); } - }); diff --git a/style.css b/style.css index e3b64d7..0729e42 100644 --- a/style.css +++ b/style.css @@ -53,6 +53,16 @@ button.success { button.error { background: #FAA; } + +.darkMode{ + display: flex; + width: 100%; + justify-content: left; + align-items: center; + gap: 0.5rem; + +} + table { margin: 1em auto; border-collapse: collapse; @@ -210,4 +220,69 @@ permission { padding: 0.5em; margin: 10px 10px; display: block; +} + + +/* Dark mode css */ + +.switch1 { + position: relative; + display: inline-block; + width: 40px; + height: 24px; +} + +/* Hide default HTML checkbox */ +.switch1 input { + opacity: 0; + width: 0; + height: 0; +} + +/* The slider */ +.slider1 { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; +} + +.slider1:before { + position: absolute; + content: ""; + height: 16px; + width: 16px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; +} + +input:checked + .slider1 { + background-color: #2196F3; +} + +input:focus + .slider1 { + box-shadow: 0 0 1px #2196F3; +} + +input:checked + .slider1:before { + -webkit-transform: translateX(16px); + -ms-transform: translateX(16px); + transform: translateX(16px); +} + +/* Rounded sliders */ +.slider1.round { + border-radius: 34px; +} + +.slider1.round:before { + border-radius: 50%; } \ No newline at end of file From 92aed4f0a6ce1d23fa7a916077531df1277ff951 Mon Sep 17 00:00:00 2001 From: amit-077 Date: Mon, 21 Oct 2024 03:49:07 +0530 Subject: [PATCH 2/3] Added dark mode --- index.html | 2 +- index.js | 47 +++++++---------- style.css | 144 +++++++++++++++++++++++++++++++++-------------------- 3 files changed, 107 insertions(+), 86 deletions(-) diff --git a/index.html b/index.html index 954117f..f133641 100644 --- a/index.html +++ b/index.html @@ -24,7 +24,7 @@

Dark Mode

diff --git a/index.js b/index.js index fd65107..1630ff3 100644 --- a/index.js +++ b/index.js @@ -1,39 +1,26 @@ // - Information about clearing settings in Chrome (can't link to chrome:// URLs) // - Indicate if permissions are already granted, if the relevant API allows it. -let mode = "light"; - -function toggleMode() { - if (mode === "light") { - document.body.style.backgroundColor = "#333"; - const buttons = document.querySelectorAll("button"); - buttons.forEach((button) => { - button.style.backgroundColor = "#666"; - button.style.color = "#f1f1f1"; - }); - document.getElementsByClassName("https")[0].style.color = "#f5f5f5"; - document.getElementsByClassName("AsyncClipAPI")[0].style.color = "#f5f5f5"; - document.getElementsByClassName("notes")[0].style.color = "#f5f5f5"; - document.getElementById("tableNotes").style.color = "#fff"; - document.getElementById("darkModeText").style.color = "#fff"; - mode = "dark"; +window.addEventListener("load", function () { + document.getElementById("darkmodeInput").addEventListener("change", () => { + if (document.body.classList.contains("dark-mode")) { + document.body.classList.remove("dark-mode"); + localStorage.setItem("theme", "light"); + } else { + document.body.classList.add("dark-mode"); + localStorage.setItem("theme", "dark"); + } + }); + + const theme = localStorage.getItem("theme"); + if (theme === "dark") { + document.body.classList.add("dark-mode"); + document.getElementById("darkmodeInput").checked = true; } else { - document.body.style.backgroundColor = "#EEE"; - const buttons = document.querySelectorAll("button"); - buttons.forEach((button) => { - button.style.backgroundColor = "#fff"; - button.style.color = "#000"; - }); - document.getElementsByClassName("https")[0].style.color = "#666"; - document.getElementsByClassName("AsyncClipAPI")[0].style.color = "#000"; - document.getElementsByClassName("notes")[0].style.color = "#000"; - document.getElementById("tableNotes").style.color = "#000"; - document.getElementById("darkModeText").style.color = "#000"; - mode = "light"; + document.body.classList.remove("dark-mode"); + document.getElementById("darkmodeInput").checked = false; } -} -window.addEventListener("load", function () { var toggle = document.querySelector("#toggle"); toggle.classList.add("instant"); if (window.location.protocol == "https:") { diff --git a/style.css b/style.css index 0729e42..89173a3 100644 --- a/style.css +++ b/style.css @@ -1,14 +1,16 @@ /* Light material design boilerplate. */ -html, body { +html, +body { width: 100%; margin: 0; padding: 0; - background: #EEEEEE; + background: #eeeeee; } /* Only apply min-height to non-print media */ @media not print { - html, body { + html, + body { min-height: 100%; } } @@ -35,32 +37,34 @@ body { } button { - background: #FFF; border: none; + background: #fff; + border: none; font-size: 1.5em; - width: 400px; padding: 0.5em; margin: 10px 10px; - box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); + width: 400px; + padding: 0.5em; + margin: 10px 10px; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); transition: all 150ms; } button:hover { - background: #FFA; + background: #ffa; cursor: pointer; - box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); transform: translateY(-2px); } button.success { - background: #AFA; + background: #afa; } button.error { - background: #FAA; + background: #faa; } -.darkMode{ +.darkMode { display: flex; width: 100%; justify-content: left; align-items: center; gap: 0.5rem; - } table { @@ -89,41 +93,38 @@ table td:first-child { } #toggle .http, -#toggle .https -{ +#toggle .https { color: rgba(0, 0, 0, 0.5); transition: color 0.25s ease-in-out; } #toggle.https .http, -#toggle.http .https -{ +#toggle.http .https { color: rgba(0, 0, 0, 0.5); } #toggle.http:not(:hover) .http { - color: #DB4437; + color: #db4437; } #toggle.https:not(:hover) .https { - color: #1AC222; + color: #1ac222; } #toggle.http:hover .https { text-decoration: underline; - color: #1AC222; + color: #1ac222; } #toggle.https:hover .http { text-decoration: underline; - color: #DB4437; + color: #db4437; } a#toggle:hover { color: black; } - .switch { display: inline-block; width: 34px; @@ -139,12 +140,10 @@ a#toggle:hover { height: 20px; margin: -3px; border-radius: 10px; - background-color: #F1F1F1; - border: - inset 0.5px rgba(255, 255, 255, 0.12), + background-color: #f1f1f1; + border: inset 0.5px rgba(255, 255, 255, 0.12), inset 0.5px rgba(255, 255, 255, 0.12); - box-shadow: - 0px 0px 2px 0px rgba(0, 0, 0, 0.12), + box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.12), 0px 2px 2px 0px rgba(0, 0, 0, 0.24); transform: translateX(10px); @@ -154,56 +153,52 @@ a#toggle:hover { #toggle.instant .switch, #toggle.instant .switch .knob, #toggle.instant .http, -#toggle.instant .https -{ +#toggle.instant .https { transition: transform 0s; } -.http:not(:hover) .switch, -.https:hover .switch -{ +.http:not(:hover) .switch, +.https:hover .switch { background-color: rgba(219, 68, 55, 0.26); } -.http:not(:hover) .switch .knob, -.https:hover .switch .knob -{ +.http:not(:hover) .switch .knob, +.https:hover .switch .knob { background-color: rgb(219, 68, 55); transform: translateX(0px); } -.http:hover .switch, -.https:not(:hover) .switch -{ +.http:hover .switch, +.https:not(:hover) .switch { background-color: rgba(29, 194, 34, 0.5); } -.http:hover .switch .knob, -.https:not(:hover) .switch .knob -{ +.http:hover .switch .knob, +.https:not(:hover) .switch .knob { background-color: rgb(29, 194, 34); transform: translateX(20px); } -.jswarning -{ +.jswarning { color: rgb(219, 68, 55); font-size: 2em; } -.permission-status, .access-status { +.permission-status, +.access-status { font-size: small; text-transform: uppercase; - padding-top: .4rem; + padding-top: 0.4rem; text-align: left; } -.permission-status > span, .access-status > span { +.permission-status > span, +.access-status > span { font-weight: 800; } .demo-instructions { - padding: .5rem 1rem; + padding: 0.5rem 1rem; margin-top: 1rem; text-align: left; border: solid 1px; @@ -214,7 +209,7 @@ a#toggle:hover { permission { background: #def0ff; - border: solid #005763; + border: solid #005763; border-radius: 5px; width: 400px; padding: 0.5em; @@ -222,7 +217,6 @@ permission { display: block; } - /* Dark mode css */ .switch1 { @@ -248,8 +242,8 @@ permission { right: 0; bottom: 0; background-color: #ccc; - -webkit-transition: .4s; - transition: .4s; + -webkit-transition: 0.4s; + transition: 0.4s; } .slider1:before { @@ -260,16 +254,16 @@ permission { left: 4px; bottom: 4px; background-color: white; - -webkit-transition: .4s; - transition: .4s; + -webkit-transition: 0.4s; + transition: 0.4s; } input:checked + .slider1 { - background-color: #2196F3; + background-color: #2196f3; } input:focus + .slider1 { - box-shadow: 0 0 1px #2196F3; + box-shadow: 0 0 1px #2196f3; } input:checked + .slider1:before { @@ -285,4 +279,44 @@ input:checked + .slider1:before { .slider1.round:before { border-radius: 50%; -} \ No newline at end of file +} + +/* Dark Mode */ + +/* Dark mode styles */ +body.dark-mode { + background: #333; + color: #eee; + transition: 0.5s all; +} + +body.dark-mode button { + background: #444; + color: #eee; + transition: 0.5s all; +} + +body.dark-mode .switch { + background-color: rgba(29, 194, 34, 0.5); + transition: 0.5s all; +} + +body.dark-mode .content { + background-color: #444; + transition: 0.5s all; +} + +body.dark-mode .slider1 { + background-color: #888; + transition: 0.5s all; +} + +body.dark-mode .slider1:before { + background-color: #eee; + transition: 0.5s all; +} + +#darkmodeInput:checked + .slider1 { + background-color: #2196f3; + transition: 0.5s all; +} From 217db0b4244814246720350678d4db10a4a4c989 Mon Sep 17 00:00:00 2001 From: amit-077 Date: Mon, 21 Oct 2024 03:58:44 +0530 Subject: [PATCH 3/3] Add dark mode support with OS preference detection and optional localStorage override --- index.js | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 1630ff3..2e6de86 100644 --- a/index.js +++ b/index.js @@ -2,25 +2,47 @@ // - Indicate if permissions are already granted, if the relevant API allows it. window.addEventListener("load", function () { - document.getElementById("darkmodeInput").addEventListener("change", () => { - if (document.body.classList.contains("dark-mode")) { - document.body.classList.remove("dark-mode"); - localStorage.setItem("theme", "light"); - } else { + function setTheme(mode) { + if (mode === "dark") { document.body.classList.add("dark-mode"); localStorage.setItem("theme", "dark"); + document.getElementById("darkmodeInput").checked = true; + } else { + document.body.classList.remove("dark-mode"); + localStorage.setItem("theme", "light"); + document.getElementById("darkmodeInput").checked = false; } - }); + } + + // Check for a stored theme in localStorage + let theme = localStorage.getItem("theme"); - const theme = localStorage.getItem("theme"); - if (theme === "dark") { - document.body.classList.add("dark-mode"); - document.getElementById("darkmodeInput").checked = true; - } else { - document.body.classList.remove("dark-mode"); - document.getElementById("darkmodeInput").checked = false; + // If there's no stored theme, detect the OS preference + if (!theme) { + const osPrefersDark = window.matchMedia( + "(prefers-color-scheme: dark)" + ).matches; + theme = osPrefersDark ? "dark" : "light"; } + // Apply the theme on page load based on the stored or detected theme + setTheme(theme); + + // Listen for changes in the OS color scheme and update if no manual override + window + .matchMedia("(prefers-color-scheme: dark)") + .addEventListener("change", (e) => { + if (!localStorage.getItem("theme")) { + setTheme(e.matches ? "dark" : "light"); + } + }); + + // Add event listener for the dark mode toggle + document.getElementById("darkmodeInput").addEventListener("change", () => { + const isDarkMode = document.body.classList.contains("dark-mode"); + setTheme(isDarkMode ? "light" : "dark"); + }); + var toggle = document.querySelector("#toggle"); toggle.classList.add("instant"); if (window.location.protocol == "https:") {