[READ-ONLY] Mirror of https://github.com/danielroe/dev-mode.dev. A site to toggle your developer mode on and off with ONE CLICK! dev-mode.dev
dev-mode developer dx
0

Configure Feed

Select the types of activity you want to include in your feed.

feat: dark mode (#3)

+198 -50
-5
.github/workflows/autofix.yml
··· 12 12 jobs: 13 13 code: 14 14 runs-on: ubuntu-latest 15 - container: 16 - image: mcr.microsoft.com/playwright:v1.51.1-noble 17 15 18 16 steps: 19 17 - uses: actions/checkout@v4 ··· 37 35 38 36 - name: 🏃 Update component test snapshots 39 37 run: pnpm test:nuxt -u 40 - 41 - - name: 🖥️ Update browser test snapshots 42 - run: pnpm test:browser --update-snapshots 43 38 44 39 - uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c
+159 -45
app/app.vue
··· 1 1 <script setup lang="ts"> 2 + import { useSound } from '@vueuse/sound' 3 + import flashlightSound from '~/assets/flashlight.mp3' 4 + 2 5 const devMode = useLocalStorage('dev-mode', () => false) 3 6 4 7 defineOgImage({ component: 'Default' }) ··· 46 49 } 47 50 } 48 51 }) 52 + 53 + const darkMode = ref(false) 54 + 55 + const { x, y } = useMouse({ 56 + type: 'client', 57 + }) 58 + 59 + const { play: playFlashlightSound } = useSound(flashlightSound) 60 + 61 + watch(darkMode, () => { 62 + playFlashlightSound() 63 + }) 49 64 </script> 50 65 51 66 <template> 52 - <div class="app-container"> 53 - <main> 54 - <h1 class="title"> 55 - dev mode 56 - </h1> 57 - <p class="subtitle"> 58 - easily turn dev mode on and off 59 - </p> 67 + <div 68 + class="root" 69 + :class="{ 70 + dark: darkMode, 71 + }" 72 + > 73 + <div class="app-container"> 74 + <main> 75 + <h1 class="title"> 76 + dev mode 77 + </h1> 78 + <p class="subtitle"> 79 + easily turn dev mode on and off 80 + </p> 60 81 61 - <div 62 - class="toggle-container" 63 - > 64 - <button 65 - class="toggle" 66 - :class="{ 'toggle-on': devMode }" 67 - type="button" 68 - role="switch" 69 - :aria-checked="devMode" 70 - aria-label="Toggle developer mode" 71 - @click="devMode = !devMode" 82 + <div 83 + class="toggle-container" 72 84 > 73 - <span class="toggle-handle" /> 74 - </button> 85 + <button 86 + class="toggle" 87 + :class="{ 'toggle-on': devMode }" 88 + type="button" 89 + role="switch" 90 + :aria-checked="devMode" 91 + aria-label="Toggle developer mode" 92 + @click="devMode = !devMode" 93 + > 94 + <span class="toggle-handle" /> 95 + </button> 96 + <p 97 + class="toggle-status" 98 + aria-hidden="true" 99 + > 100 + {{ devMode ? 'ON' : 'OFF' }} 101 + </p> 102 + </div> 103 + 75 104 <p 76 - class="toggle-status" 77 - aria-hidden="true" 105 + class="status-message" 106 + aria-live="polite" 78 107 > 79 - {{ devMode ? 'ON' : 'OFF' }} 108 + developer mode is currently <span :class="devMode ? 'on' : 'off'">{{ devMode ? 'ON' : 'OFF' }}</span> 80 109 </p> 81 - </div> 110 + </main> 82 111 83 - <p 84 - class="status-message" 85 - aria-live="polite" 112 + <div 113 + class="toggle-dark-mode" 114 + title="Toggle dark mode" 115 + @click="darkMode = !darkMode" 86 116 > 87 - developer mode is currently <span :class="devMode ? 'on' : 'off'">{{ devMode ? 'ON' : 'OFF' }}</span> 88 - </p> 89 - </main> 117 + <svg 118 + xmlns="http://www.w3.org/2000/svg" 119 + width="32" 120 + height="32" 121 + viewBox="0 0 24 24" 122 + ><!-- Icon from Lucide by Lucide Contributors - https://github.com/lucide-icons/lucide/blob/main/LICENSE --><path 123 + fill="none" 124 + stroke="currentColor" 125 + stroke-linecap="round" 126 + stroke-linejoin="round" 127 + stroke-width="2" 128 + d="M12 3a6 6 0 0 0 9 9a9 9 0 1 1-9-9" 129 + /></svg> 130 + </div> 90 131 91 - <footer> 92 - <a 93 - class="hover:underline" 94 - href="https://github.com/danielroe/dev-mode.dev" 95 - aria-label="View source code on GitHub" 96 - >source</a> 97 - &middot; 98 - made with ❤️ by <a 99 - class="font-semibold hover:underline" 100 - href="https://bsky.app/profile/danielroe.dev" 101 - aria-label="Daniel Roe on Bluesky" 132 + <footer> 133 + <a 134 + class="hover:underline" 135 + href="https://github.com/danielroe/dev-mode.dev" 136 + aria-label="View source code on GitHub" 137 + >source</a> 138 + &middot; 139 + made with ❤️ by <a 140 + class="font-semibold hover:underline" 141 + href="https://bsky.app/profile/danielroe.dev" 142 + aria-label="Daniel Roe on Bluesky" 143 + > 144 + @danielroe.dev 145 + </a> 146 + </footer> 147 + </div> 148 + 149 + <div 150 + v-if="darkMode" 151 + class="dark-light" 152 + > 153 + <div 154 + class="flashlight" 155 + :style="{ 156 + transform: `translate(${x}px, ${y}px)`, 157 + }" 102 158 > 103 - @danielroe.dev 104 - </a> 105 - </footer> 159 + <img 160 + src="~/assets/flashlight.png" 161 + alt="Flashlight" 162 + > 163 + </div> 164 + </div> 106 165 </div> 107 166 </template> 108 167 109 168 <style scoped> 169 + a { 170 + cursor: pointer; 171 + } 172 + 110 173 .app-container { 111 174 min-height: 100vh; 112 175 display: flex; ··· 208 271 .off { 209 272 color: #555; 210 273 font-weight: bold; 274 + } 275 + 276 + .toggle-dark-mode { 277 + position: fixed; 278 + top: 1rem; 279 + right: 1rem; 280 + background-color: #fff; 281 + border-radius: 100%; 282 + display: flex; 283 + align-items: center; 284 + justify-content: center; 285 + width: 50px; 286 + height: 50px; 287 + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 288 + cursor: pointer; 289 + 290 + &:hover { 291 + background-color: #2759cf; 292 + color: #fff; 293 + } 294 + 295 + visibility: hidden; 296 + 297 + @media (hover: hover) { 298 + & { 299 + visibility: visible; 300 + } 301 + } 302 + } 303 + 304 + .dark { 305 + cursor: none; 306 + } 307 + 308 + .dark-light { 309 + position: fixed; 310 + top: 0; 311 + left: 0; 312 + width: 100%; 313 + height: 100%; 314 + background-color: black; 315 + pointer-events: none; 316 + mix-blend-mode: multiply; 317 + } 318 + 319 + .flashlight { 320 + position: fixed; 321 + 322 + & img { 323 + transform: translate(-50%, -50%); 324 + } 211 325 } 212 326 213 327 footer {
app/assets/flashlight.mp3

This is a binary file and will not be displayed.

app/assets/flashlight.png

This is a binary file and will not be displayed.

+1
package.json
··· 28 28 "@nuxt/scripts": "^0.11.5", 29 29 "@nuxtjs/html-validator": "^2.1.0", 30 30 "@vueuse/nuxt": "13.1.0", 31 + "@vueuse/sound": "^2.1.3", 31 32 "nuxt": "^3.16.1", 32 33 "nuxt-og-image": "^5.1.1", 33 34 "nuxt-time": "^1.0.3",
+38
pnpm-lock.yaml
··· 26 26 '@vueuse/nuxt': 27 27 specifier: 13.1.0 28 28 version: 13.1.0(magicast@0.3.5)(nuxt@3.16.2(@parcel/watcher@2.5.1)(@types/node@22.14.0)(db0@0.3.1)(eslint@9.24.0(jiti@2.4.2))(ioredis@5.6.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.39.0)(terser@5.39.0)(typescript@5.8.2)(vite@6.2.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1))(vue-tsc@2.2.8(typescript@5.8.2))(yaml@2.7.1))(vue@3.5.13(typescript@5.8.2)) 29 + '@vueuse/sound': 30 + specifier: ^2.1.3 31 + version: 2.1.3(vue@3.5.13(typescript@5.8.2)) 29 32 nuxt: 30 33 specifier: ^3.16.1 31 34 version: 3.16.2(@parcel/watcher@2.5.1)(@types/node@22.14.0)(db0@0.3.1)(eslint@9.24.0(jiti@2.4.2))(ioredis@5.6.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.39.0)(terser@5.39.0)(typescript@5.8.2)(vite@6.2.5(@types/node@22.14.0)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1))(vue-tsc@2.2.8(typescript@5.8.2))(yaml@2.7.1) ··· 1502 1505 peerDependencies: 1503 1506 vue: ^3.5.0 1504 1507 1508 + '@vueuse/sound@2.1.3': 1509 + resolution: {integrity: sha512-yZW1dzMJqCp57+ZM1tJ2oPye4RJvWhzkUpGvokB5fhk/jAmOwKGbdvm8O7dJ/YAmP+eLFCBQmELjso6sXSfnAg==} 1510 + peerDependencies: 1511 + '@vue/composition-api': ^1.0.0-rc.1 1512 + vue: ^2.0.0 || >=3.0.0 1513 + peerDependenciesMeta: 1514 + '@vue/composition-api': 1515 + optional: true 1516 + 1505 1517 abbrev@2.0.0: 1506 1518 resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} 1507 1519 engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} ··· 2588 2600 hosted-git-info@7.0.2: 2589 2601 resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} 2590 2602 engines: {node: ^16.14.0 || >=18.0.0} 2603 + 2604 + howler@2.2.4: 2605 + resolution: {integrity: sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==} 2591 2606 2592 2607 html-validate@9.4.2: 2593 2608 resolution: {integrity: sha512-lvorU3Q320MMD6ryh0FupMJ5DOKsNKxwdKba+ig4cUYEBQ3SUnANBMCv5OaxwKqd2VCKQPlveXb3K1zqJsfV0Q==} ··· 4439 4454 vue-component-type-helpers@2.2.8: 4440 4455 resolution: {integrity: sha512-4bjIsC284coDO9om4HPA62M7wfsTvcmZyzdfR0aUlFXqq4tXxM1APyXpNVxPC8QazKw9OhmZNHBVDA6ODaZsrA==} 4441 4456 4457 + vue-demi@0.14.10: 4458 + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} 4459 + engines: {node: '>=12'} 4460 + hasBin: true 4461 + peerDependencies: 4462 + '@vue/composition-api': ^1.0.0-rc.1 4463 + vue: ^3.0.0-0 || ^2.6.0 4464 + peerDependenciesMeta: 4465 + '@vue/composition-api': 4466 + optional: true 4467 + 4442 4468 vue-devtools-stub@0.1.0: 4443 4469 resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} 4444 4470 ··· 6333 6359 dependencies: 6334 6360 vue: 3.5.13(typescript@5.8.2) 6335 6361 6362 + '@vueuse/sound@2.1.3(vue@3.5.13(typescript@5.8.2))': 6363 + dependencies: 6364 + howler: 2.2.4 6365 + vue: 3.5.13(typescript@5.8.2) 6366 + vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2)) 6367 + 6336 6368 abbrev@2.0.0: {} 6337 6369 6338 6370 abbrev@3.0.0: {} ··· 7478 7510 hosted-git-info@7.0.2: 7479 7511 dependencies: 7480 7512 lru-cache: 10.4.3 7513 + 7514 + howler@2.2.4: {} 7481 7515 7482 7516 html-validate@9.4.2(vitest@3.1.1(@types/node@22.14.0)(happy-dom@17.4.4)(jiti@2.4.2)(terser@5.39.0)(yaml@2.7.1)): 7483 7517 dependencies: ··· 9639 9673 ufo: 1.5.4 9640 9674 9641 9675 vue-component-type-helpers@2.2.8: {} 9676 + 9677 + vue-demi@0.14.10(vue@3.5.13(typescript@5.8.2)): 9678 + dependencies: 9679 + vue: 3.5.13(typescript@5.8.2) 9642 9680 9643 9681 vue-devtools-stub@0.1.0: {} 9644 9682
test/browser/index.spec.ts-snapshots/home-page-1-linux.png

This is a binary file and will not be displayed.