nuxtseo-layer-devtools 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -216,7 +216,7 @@ h1, h2, h3, h4, h5, h6 {
216
216
  }
217
217
 
218
218
  .dark .glass {
219
- background: oklch(9% 0.005 260 / 0.85);
219
+ background: oklch(9% 0.005 260 / 0.7);
220
220
  }
221
221
 
222
222
  /* Code block styling */
@@ -565,19 +565,29 @@ html.dark {
565
565
  flex: 1;
566
566
  display: flex;
567
567
  flex-direction: column;
568
- padding: 0.75rem;
569
568
  min-height: calc(100vh - 60px);
570
569
  }
571
570
 
571
+ .devtools-main-content {
572
+ display: flex;
573
+ flex-direction: column;
574
+ width: 100%;
575
+ max-width: 80rem;
576
+ margin: 0 auto;
577
+ padding: 0.75rem 1rem;
578
+ }
579
+
572
580
  @media (min-width: 640px) {
573
- .devtools-main {
574
- padding: 1rem;
581
+ .devtools-main-content {
582
+ padding: 1rem 1.25rem;
575
583
  }
576
584
  }
577
585
 
578
586
  @media (max-height: 600px) {
579
587
  .devtools-main {
580
- padding: 0;
581
588
  min-height: 0;
582
589
  }
590
+ .devtools-main-content {
591
+ padding: 0;
592
+ }
583
593
  }
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
2
+ import { onClickOutside } from '@vueuse/core'
3
+ import { computed, ref } from 'vue'
3
4
  import { colorMode } from '../composables/rpc'
4
5
  import { hasProductionUrl, isProductionMode, previewSource, productionUrl } from '../composables/state'
5
6
 
@@ -58,6 +59,15 @@ const productionHostname = computed(() => {
58
59
  })
59
60
 
60
61
  const isRouteNav = computed(() => navItems.some(item => item.to))
62
+
63
+ const modeDropdownOpen = ref(false)
64
+ const modeDropdownRef = ref<HTMLElement>()
65
+ onClickOutside(modeDropdownRef, () => { modeDropdownOpen.value = false })
66
+
67
+ function selectMode(mode: 'local' | 'production') {
68
+ previewSource.value = mode
69
+ modeDropdownOpen.value = false
70
+ }
61
71
  </script>
62
72
 
63
73
  <template>
@@ -94,15 +104,8 @@ const isRouteNav = computed(() => navItems.some(item => item.to))
94
104
  >
95
105
  v{{ version }}
96
106
  </UBadge>
97
- <UDropdownMenu
98
- v-if="hasProductionUrl"
99
- :items="[
100
- { label: 'Local', icon: 'carbon:laptop', onSelect: () => previewSource = 'local' },
101
- { label: 'Production', icon: 'carbon:cloud', hostname: productionHostname, onSelect: () => previewSource = 'production' },
102
- ]"
103
- :portal="false"
104
- >
105
- <button type="button" class="devtools-mode-btn">
107
+ <div v-if="hasProductionUrl" ref="modeDropdownRef" class="mode-dropdown-wrapper">
108
+ <button type="button" class="devtools-mode-btn" @click="modeDropdownOpen = !modeDropdownOpen">
106
109
  <UIcon :name="isProductionMode ? 'carbon:cloud' : 'carbon:laptop'" class="w-3.5 h-3.5" />
107
110
  <span class="hidden sm:inline">{{ isProductionMode ? 'Production' : 'Local' }}</span>
108
111
  <template v-if="isProductionMode">
@@ -111,16 +114,25 @@ const isRouteNav = computed(() => navItems.some(item => item.to))
111
114
  {{ productionHostname }}
112
115
  </span>
113
116
  </template>
114
- <UIcon name="carbon:chevron-down" class="w-3 h-3 opacity-50" />
117
+ <UIcon name="carbon:chevron-down" class="w-3 h-3 opacity-50 transition-transform" :class="modeDropdownOpen ? 'rotate-180' : ''" />
115
118
  </button>
116
- <template #item-label="{ item }">
117
- <span>{{ item.label }}</span>
118
- <span v-if="(item as any).hostname" class="devtools-production-badge text-[10px]">
119
- <span class="devtools-production-dot" />
120
- {{ (item as any).hostname }}
121
- </span>
122
- </template>
123
- </UDropdownMenu>
119
+ <Transition name="dropdown">
120
+ <div v-if="modeDropdownOpen" class="mode-dropdown-menu">
121
+ <button type="button" class="mode-dropdown-item" @click="selectMode('local')">
122
+ <UIcon name="carbon:laptop" class="w-4 h-4" />
123
+ <span>Local</span>
124
+ </button>
125
+ <button type="button" class="mode-dropdown-item" @click="selectMode('production')">
126
+ <UIcon name="carbon:cloud" class="w-4 h-4" />
127
+ <span>Production</span>
128
+ <span class="devtools-production-badge text-[10px]">
129
+ <span class="devtools-production-dot" />
130
+ {{ productionHostname }}
131
+ </span>
132
+ </button>
133
+ </div>
134
+ </Transition>
135
+ </div>
124
136
  </div>
125
137
  </div>
126
138
 
@@ -206,7 +218,7 @@ const isRouteNav = computed(() => navItems.some(item => item.to))
206
218
 
207
219
  <!-- Main Content -->
208
220
  <div class="devtools-main">
209
- <main class="mx-auto flex flex-col w-full max-w-7xl">
221
+ <main class="devtools-main-content">
210
222
  <DevtoolsLoading v-if="loading" />
211
223
  <div v-show="!loading">
212
224
  <slot />
@@ -216,3 +228,59 @@ const isRouteNav = computed(() => navItems.some(item => item.to))
216
228
  </div>
217
229
  </UApp>
218
230
  </template>
231
+
232
+ <style scoped>
233
+ .mode-dropdown-wrapper {
234
+ position: relative;
235
+ }
236
+
237
+ .mode-dropdown-menu {
238
+ position: absolute;
239
+ top: calc(100% + 6px);
240
+ left: 0;
241
+ min-width: 180px;
242
+ padding: 4px;
243
+ border-radius: var(--radius-md);
244
+ border: 1px solid var(--color-border);
245
+ background: var(--color-surface-elevated);
246
+ box-shadow: 0 8px 24px oklch(0% 0 0 / 0.12);
247
+ z-index: 100;
248
+ }
249
+
250
+ .dark .mode-dropdown-menu {
251
+ box-shadow: 0 8px 24px oklch(0% 0 0 / 0.4);
252
+ }
253
+
254
+ .mode-dropdown-item {
255
+ display: flex;
256
+ align-items: center;
257
+ gap: 0.5rem;
258
+ width: 100%;
259
+ padding: 0.4rem 0.625rem;
260
+ font-size: 0.75rem;
261
+ font-weight: 500;
262
+ color: var(--color-text-muted);
263
+ border-radius: var(--radius-sm);
264
+ cursor: pointer;
265
+ transition: background 100ms, color 100ms;
266
+ }
267
+
268
+ .mode-dropdown-item:hover {
269
+ background: var(--color-surface-sunken);
270
+ color: var(--color-text);
271
+ }
272
+
273
+ .dropdown-enter-active {
274
+ transition: opacity 150ms ease, transform 150ms ease;
275
+ }
276
+
277
+ .dropdown-leave-active {
278
+ transition: opacity 100ms ease, transform 100ms ease;
279
+ }
280
+
281
+ .dropdown-enter-from,
282
+ .dropdown-leave-to {
283
+ opacity: 0;
284
+ transform: translateY(-4px);
285
+ }
286
+ </style>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxtseo-layer-devtools",
3
3
  "type": "module",
4
- "version": "0.2.2",
4
+ "version": "0.2.3",
5
5
  "description": "Shared Nuxt layer for Nuxt SEO devtools clients.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",