vuetify-nuxt-module 0.15.2 → 0.16.1

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.
package/dist/module.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "nuxt": ">=3.9.0",
6
6
  "bridge": false
7
7
  },
8
- "version": "0.15.2"
8
+ "version": "0.16.1"
9
9
  }
package/dist/module.mjs CHANGED
@@ -14,7 +14,7 @@ import { pathToFileURL } from 'node:url';
14
14
  import { parseQuery, parseURL } from 'ufo';
15
15
  import destr from 'destr';
16
16
 
17
- const version = "0.15.2";
17
+ const version = "0.16.1";
18
18
 
19
19
  const VIRTUAL_VUETIFY_CONFIGURATION = "virtual:vuetify-configuration";
20
20
  const RESOLVED_VIRTUAL_VUETIFY_CONFIGURATION = `/@nuxt-vuetify-configuration/${VIRTUAL_VUETIFY_CONFIGURATION.slice("virtual:".length)}`;
@@ -7,12 +7,14 @@ export interface ClientHintRequestFeatures {
7
7
  prefersReducedMotionAvailable: boolean
8
8
  viewportHeightAvailable: boolean
9
9
  viewportWidthAvailable: boolean
10
+ devicePixelRatioAvailable: boolean
10
11
  }
11
12
  export interface SSRClientHints extends ClientHintRequestFeatures {
12
13
  prefersColorScheme?: 'dark' | 'light' | 'no-preference'
13
14
  prefersReducedMotion?: 'no-preference' | 'reduce'
14
15
  viewportHeight?: number
15
16
  viewportWidth?: number
17
+ devicePixelRatio?: number
16
18
  colorSchemeFromCookie?: string
17
19
  colorSchemeCookie?: string
18
20
  }
@@ -44,46 +44,46 @@ const plugin = defineNuxtPlugin({
44
44
  if (viewportSize && viewportWidthAvailable)
45
45
  window.location.reload();
46
46
  }
47
- if (viewportSize || prefersColorScheme && prefersColorSchemeOptions) {
48
- nuxtApp.hook("vuetify:before-create", ({ vuetifyOptions }) => {
49
- if (viewportSize) {
50
- const clientWidth = state.value.viewportWidth;
51
- const clientHeight = state.value.viewportHeight;
52
- vuetifyOptions.ssr = typeof clientWidth === "number" ? {
53
- clientWidth,
54
- clientHeight
55
- } : true;
56
- }
57
- if (prefersColorScheme && prefersColorSchemeOptions) {
58
- if (vuetifyOptions.theme === false) {
59
- vuetifyOptions.theme = { defaultTheme: state.value.colorSchemeFromCookie ?? prefersColorSchemeOptions.defaultTheme };
60
- } else {
61
- vuetifyOptions.theme = vuetifyOptions.theme ?? {};
62
- vuetifyOptions.theme.defaultTheme = state.value.colorSchemeFromCookie ?? prefersColorSchemeOptions.defaultTheme;
63
- }
64
- }
65
- });
47
+ nuxtApp.hook("vuetify:before-create", ({ vuetifyOptions }) => {
48
+ if (viewportSize) {
49
+ const clientWidth = state.value.viewportWidth;
50
+ const clientHeight = state.value.viewportHeight;
51
+ vuetifyOptions.ssr = typeof clientWidth === "number" ? {
52
+ clientWidth,
53
+ clientHeight
54
+ } : true;
55
+ } else {
56
+ vuetifyOptions.ssr = true;
57
+ }
66
58
  if (prefersColorScheme && prefersColorSchemeOptions) {
67
- const themeCookie = state.value.colorSchemeCookie;
68
- if (themeCookie) {
69
- nuxtApp.hook("app:beforeMount", () => {
70
- const vuetify = useNuxtApp().$vuetify;
71
- const cookieName = prefersColorSchemeOptions.cookieName;
72
- const parseCookieName = `${cookieName}=`;
73
- const cookieEntry = `${parseCookieName}${state.value.colorSchemeFromCookie ?? prefersColorSchemeOptions.defaultTheme};`;
74
- watch(vuetify.theme.global.name, (newThemeName) => {
75
- document.cookie = themeCookie.replace(cookieEntry, `${cookieName}=${newThemeName};`);
76
- });
77
- if (prefersColorSchemeOptions.useBrowserThemeOnly) {
78
- const { darkThemeName, lightThemeName } = prefersColorSchemeOptions;
79
- const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
80
- prefersDark.addEventListener("change", (e) => {
81
- vuetify.theme.global.name.value = e.matches ? darkThemeName : lightThemeName;
82
- });
83
- }
84
- });
59
+ if (vuetifyOptions.theme === false) {
60
+ vuetifyOptions.theme = { defaultTheme: state.value.colorSchemeFromCookie ?? prefersColorSchemeOptions.defaultTheme };
61
+ } else {
62
+ vuetifyOptions.theme = vuetifyOptions.theme ?? {};
63
+ vuetifyOptions.theme.defaultTheme = state.value.colorSchemeFromCookie ?? prefersColorSchemeOptions.defaultTheme;
85
64
  }
86
65
  }
66
+ });
67
+ if (prefersColorScheme && prefersColorSchemeOptions) {
68
+ const themeCookie = state.value.colorSchemeCookie;
69
+ if (themeCookie) {
70
+ nuxtApp.hook("app:beforeMount", () => {
71
+ const vuetify = useNuxtApp().$vuetify;
72
+ const cookieName = prefersColorSchemeOptions.cookieName;
73
+ const parseCookieName = `${cookieName}=`;
74
+ const cookieEntry = `${parseCookieName}${state.value.colorSchemeFromCookie ?? prefersColorSchemeOptions.defaultTheme};`;
75
+ watch(vuetify.theme.global.name, (newThemeName) => {
76
+ document.cookie = themeCookie.replace(cookieEntry, `${cookieName}=${newThemeName};`);
77
+ });
78
+ if (prefersColorSchemeOptions.useBrowserThemeOnly) {
79
+ const { darkThemeName, lightThemeName } = prefersColorSchemeOptions;
80
+ const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
81
+ prefersDark.addEventListener("change", (e) => {
82
+ vuetify.theme.global.name.value = e.matches ? darkThemeName : lightThemeName;
83
+ });
84
+ }
85
+ });
86
+ }
87
87
  }
88
88
  return {
89
89
  provide: reactive({
@@ -17,16 +17,18 @@ const AcceptClientHintsHeaders = {
17
17
  prefersColorScheme: "Sec-CH-Prefers-Color-Scheme",
18
18
  prefersReducedMotion: "Sec-CH-Prefers-Reduced-Motion",
19
19
  viewportHeight: "Sec-CH-Viewport-Height",
20
- viewportWidth: "Sec-CH-Viewport-Width"
20
+ viewportWidth: "Sec-CH-Viewport-Width",
21
+ devicePixelRatio: "Sec-CH-DPR"
21
22
  };
22
23
  const AcceptClientHintsRequestHeaders = Object.entries(AcceptClientHintsHeaders).reduce((acc, [key, value]) => {
23
24
  acc[key] = value.toLowerCase();
24
25
  return acc;
25
26
  }, {});
26
- const HttpRequestHeaders = Array.from(Object.values(AcceptClientHintsRequestHeaders)).concat("user-agent", "cookie");
27
+ const SecChUaMobile = "Sec-CH-UA-Mobile".toLowerCase();
28
+ const HttpRequestHeaders = Array.from(Object.values(AcceptClientHintsRequestHeaders)).concat("user-agent", "cookie", SecChUaMobile);
27
29
  const plugin = defineNuxtPlugin({
28
30
  name: "vuetify:client-hints:server:plugin",
29
- order: -25,
31
+ order: 24,
30
32
  parallel: true,
31
33
  setup(nuxtApp) {
32
34
  const state = useState(VuetifyHTTPClientHints);
@@ -75,19 +77,24 @@ const chromiumBasedBrowserFeatures = {
75
77
  prefersColorScheme: (_, v) => v[0] >= 93,
76
78
  prefersReducedMotion: (_, v) => v[0] >= 108,
77
79
  viewportHeight: (_, v) => v[0] >= 108,
78
- viewportWidth: (_, v) => v[0] >= 108
80
+ viewportWidth: (_, v) => v[0] >= 108,
81
+ devicePixelRatio: (_, v) => v[0] >= 46
79
82
  };
80
83
  const allowedBrowsers = [
81
84
  // 'edge',
82
85
  // 'edge-ios',
83
86
  ["chrome", chromiumBasedBrowserFeatures],
84
- ["edge-chromium", chromiumBasedBrowserFeatures],
87
+ ["edge-chromium", {
88
+ ...chromiumBasedBrowserFeatures,
89
+ devicePixelRatio: (_, v) => v[0] >= 79
90
+ }],
85
91
  ["chromium-webview", chromiumBasedBrowserFeatures],
86
92
  ["opera", {
87
93
  prefersColorScheme: (android, v) => v[0] >= (android ? 66 : 79),
88
94
  prefersReducedMotion: (android, v) => v[0] >= (android ? 73 : 94),
89
95
  viewportHeight: (android, v) => v[0] >= (android ? 73 : 94),
90
- viewportWidth: (android, v) => v[0] >= (android ? 73 : 94)
96
+ viewportWidth: (android, v) => v[0] >= (android ? 73 : 94),
97
+ devicePixelRatio: (_, v) => v[0] >= 33
91
98
  }]
92
99
  ];
93
100
  const ClientHeaders = ["Accept-CH", "Vary", "Critical-CH"];
@@ -111,13 +118,14 @@ function browserFeatureAvailable(userAgent, feature) {
111
118
  return false;
112
119
  }
113
120
  }
114
- function lookupClientHints(userAgent, ssrClientHintsConfiguration2) {
121
+ function lookupClientHints(userAgent, ssrClientHintsConfiguration2, headers) {
115
122
  const features = {
116
123
  firstRequest: true,
117
124
  prefersColorSchemeAvailable: false,
118
125
  prefersReducedMotionAvailable: false,
119
126
  viewportHeightAvailable: false,
120
- viewportWidthAvailable: false
127
+ viewportWidthAvailable: false,
128
+ devicePixelRatioAvailable: false
121
129
  };
122
130
  if (userAgent == null || userAgent.type !== "browser")
123
131
  return features;
@@ -128,11 +136,14 @@ function lookupClientHints(userAgent, ssrClientHintsConfiguration2) {
128
136
  if (ssrClientHintsConfiguration2.viewportSize) {
129
137
  features.viewportHeightAvailable = browserFeatureAvailable(userAgent, "viewportHeight");
130
138
  features.viewportWidthAvailable = browserFeatureAvailable(userAgent, "viewportWidth");
139
+ const mobileHeader = headers[SecChUaMobile];
140
+ if (mobileHeader === "?1")
141
+ features.devicePixelRatioAvailable = browserFeatureAvailable(userAgent, "devicePixelRatio");
131
142
  }
132
143
  return features;
133
144
  }
134
145
  function collectClientHints(userAgent, ssrClientHintsConfiguration2, headers) {
135
- const hints = lookupClientHints(userAgent, ssrClientHintsConfiguration2);
146
+ const hints = lookupClientHints(userAgent, ssrClientHintsConfiguration2, headers);
136
147
  if (ssrClientHintsConfiguration2.prefersColorScheme) {
137
148
  if (ssrClientHintsConfiguration2.prefersColorSchemeOptions) {
138
149
  const cookieName = ssrClientHintsConfiguration2.prefersColorSchemeOptions.cookieName;
@@ -193,6 +204,22 @@ function collectClientHints(userAgent, ssrClientHintsConfiguration2, headers) {
193
204
  } else {
194
205
  hints.viewportWidth = ssrClientHintsConfiguration2.clientWidth;
195
206
  }
207
+ if (hints.devicePixelRatioAvailable && ssrClientHintsConfiguration2.viewportSize) {
208
+ const header = headers[AcceptClientHintsRequestHeaders.devicePixelRatio];
209
+ if (header) {
210
+ hints.firstRequest = false;
211
+ try {
212
+ hints.devicePixelRatio = Number.parseFloat(header);
213
+ if (!Number.isNaN(hints.devicePixelRatio) && hints.devicePixelRatio > 0) {
214
+ if (typeof hints.viewportWidth === "number")
215
+ hints.viewportWidth = Math.round(hints.viewportWidth / hints.devicePixelRatio);
216
+ if (typeof hints.viewportHeight === "number")
217
+ hints.viewportHeight = Math.round(hints.viewportHeight / hints.devicePixelRatio);
218
+ }
219
+ } catch {
220
+ }
221
+ }
222
+ }
196
223
  return hints;
197
224
  }
198
225
  function writeClientHintHeaders(key, headers) {
@@ -209,6 +236,8 @@ function writeClientHintsResponseHeaders(clientHintsRequest, ssrClientHintsConfi
209
236
  if (ssrClientHintsConfiguration2.viewportSize && clientHintsRequest.viewportHeightAvailable && clientHintsRequest.viewportWidthAvailable) {
210
237
  writeClientHintHeaders(AcceptClientHintsHeaders.viewportHeight, headers);
211
238
  writeClientHintHeaders(AcceptClientHintsHeaders.viewportWidth, headers);
239
+ if (clientHintsRequest.devicePixelRatioAvailable)
240
+ writeClientHintHeaders(AcceptClientHintsHeaders.devicePixelRatio, headers);
212
241
  }
213
242
  if (Object.keys(headers).length === 0)
214
243
  return;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vuetify-nuxt-module",
3
3
  "type": "module",
4
- "version": "0.15.2",
4
+ "version": "0.16.1",
5
5
  "packageManager": "pnpm@9.5.0",
6
6
  "description": "Zero-Config Nuxt Module for Vuetify",
7
7
  "author": "userquin <userquin@gmail.com>",