ds-one 0.3.0-alpha.1 → 0.3.0-alpha.2
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/DS1/0-face/device.ts +180 -34
- package/DS1/1-root/one.css +1 -1
- package/DS1/index.ts +0 -1
- package/README.md +2 -2
- package/dist/0-face/device.d.ts +47 -1
- package/dist/0-face/device.d.ts.map +1 -1
- package/dist/0-face/device.js +132 -25
- package/dist/ds-one.bundle.js +1421 -1436
- package/dist/ds-one.bundle.js.map +1 -1
- package/dist/ds-one.bundle.min.js +1206 -1217
- package/dist/ds-one.bundle.min.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/package.json +1 -1
- package/DS1/0-face/scaling.ts +0 -152
- package/dist/0-face/scaling.d.ts +0 -48
- package/dist/0-face/scaling.d.ts.map +0 -1
- package/dist/0-face/scaling.js +0 -114
- package/dist/2-core/styles/ds-banner.css +0 -77
- package/dist/2-core/styles/ds-button.css +0 -67
- package/dist/2-core/styles/ds-cycle.css +0 -21
- package/dist/2-core/styles/ds-date.css +0 -9
- package/dist/2-core/styles/ds-gap.css +0 -93
- package/dist/2-core/styles/ds-icon.css +0 -30
- package/dist/2-core/styles/ds-input.css +0 -46
- package/dist/2-core/styles/ds-pagedots.css +0 -26
- package/dist/2-core/styles/ds-text.css +0 -29
- package/dist/2-core/styles/ds-tooltip.css +0 -49
- package/dist/3-unit/styles/ds-accordion.css +0 -46
- package/dist/3-unit/styles/ds-list.css +0 -9
- package/dist/3-unit/styles/ds-row.css +0 -19
- package/dist/3-unit/styles/ds-table.css +0 -80
- package/dist/4-page/styles/ds-container.css +0 -35
- package/dist/4-page/styles/ds-grid.css +0 -56
- package/dist/4-page/styles/ds-layout.css +0 -251
- package/dist/ds-one.bundle.css +0 -700
- package/dist/ds-one.bundle.css.map +0 -7
- package/dist/ds-one.bundle.min.css +0 -2
- package/dist/ds-one.bundle.min.css.map +0 -7
package/DS1/0-face/device.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Device detection and
|
|
1
|
+
// device.ts
|
|
2
|
+
// Device detection, context utilities, and responsive scaling
|
|
3
|
+
|
|
4
|
+
import { signal } from "@lit-labs/signals";
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Types
|
|
8
|
+
// ============================================================================
|
|
3
9
|
|
|
4
10
|
export type DeviceType = "mobile" | "tablet" | "desktop";
|
|
5
11
|
|
|
@@ -14,6 +20,36 @@ export interface DeviceInfo {
|
|
|
14
20
|
screenHeight: number;
|
|
15
21
|
}
|
|
16
22
|
|
|
23
|
+
export type ScalingMode = "auto" | "fixed" | "fluid";
|
|
24
|
+
|
|
25
|
+
export interface ScalingConfig {
|
|
26
|
+
mode: ScalingMode;
|
|
27
|
+
baseWidth: number;
|
|
28
|
+
minScale: number;
|
|
29
|
+
maxScale: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// Configuration & Signals
|
|
34
|
+
// ============================================================================
|
|
35
|
+
|
|
36
|
+
const defaultScalingConfig: ScalingConfig = {
|
|
37
|
+
mode: "auto",
|
|
38
|
+
baseWidth: 280,
|
|
39
|
+
minScale: 0.75,
|
|
40
|
+
maxScale: 2.0,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Reactive scaling factor signal */
|
|
44
|
+
export const scalingFactor = signal<number>(1);
|
|
45
|
+
|
|
46
|
+
/** Current scaling configuration */
|
|
47
|
+
export const scalingConfig = signal<ScalingConfig>(defaultScalingConfig);
|
|
48
|
+
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// Device Detection
|
|
51
|
+
// ============================================================================
|
|
52
|
+
|
|
17
53
|
/**
|
|
18
54
|
* Comprehensive mobile device detection
|
|
19
55
|
* Combines user agent detection, touch capability, and viewport size
|
|
@@ -80,48 +116,148 @@ export function getDeviceInfo(): DeviceInfo {
|
|
|
80
116
|
};
|
|
81
117
|
}
|
|
82
118
|
|
|
119
|
+
// ============================================================================
|
|
120
|
+
// Scaling
|
|
121
|
+
// ============================================================================
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Calculate the scaling factor based on viewport width
|
|
125
|
+
* @param viewportWidth - Current viewport width in pixels
|
|
126
|
+
* @param config - Scaling configuration
|
|
127
|
+
* @returns The calculated scaling factor
|
|
128
|
+
*/
|
|
129
|
+
export function calculateScalingFactor(
|
|
130
|
+
viewportWidth: number,
|
|
131
|
+
config: ScalingConfig = scalingConfig.get()
|
|
132
|
+
): number {
|
|
133
|
+
if (config.mode === "fixed") {
|
|
134
|
+
return 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const rawScale = viewportWidth / config.baseWidth;
|
|
138
|
+
const clampedScale = Math.max(
|
|
139
|
+
config.minScale,
|
|
140
|
+
Math.min(config.maxScale, rawScale)
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
return Number(clampedScale.toFixed(3));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Set the scaling configuration
|
|
148
|
+
* @param config - Partial scaling configuration to apply
|
|
149
|
+
*/
|
|
150
|
+
export function setScalingConfig(config: Partial<ScalingConfig>): void {
|
|
151
|
+
const currentConfig = scalingConfig.get();
|
|
152
|
+
const newConfig = { ...currentConfig, ...config };
|
|
153
|
+
scalingConfig.set(newConfig);
|
|
154
|
+
|
|
155
|
+
// Recalculate scaling factor if in browser
|
|
156
|
+
if (typeof window !== "undefined") {
|
|
157
|
+
updateScalingFactor();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
83
161
|
/**
|
|
84
|
-
*
|
|
162
|
+
* Update the scaling factor based on current viewport
|
|
163
|
+
* Desktop always uses factor 1; mobile uses computed factor
|
|
164
|
+
*/
|
|
165
|
+
export function updateScalingFactor(): void {
|
|
166
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const isMobile = detectMobileDevice();
|
|
171
|
+
|
|
172
|
+
// Desktop: always use factor 1
|
|
173
|
+
if (!isMobile) {
|
|
174
|
+
const factor = 1;
|
|
175
|
+
scalingFactor.set(factor);
|
|
176
|
+
document.documentElement.style.setProperty("--sf", factor.toString());
|
|
177
|
+
window.dispatchEvent(
|
|
178
|
+
new CustomEvent("scaling-changed", {
|
|
179
|
+
detail: { scalingFactor: factor, config: scalingConfig.get() },
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Mobile: compute scaling based on viewport
|
|
186
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
187
|
+
const config = scalingConfig.get();
|
|
188
|
+
const newFactor = calculateScalingFactor(viewportWidth, config);
|
|
189
|
+
|
|
190
|
+
scalingFactor.set(newFactor);
|
|
191
|
+
document.documentElement.style.setProperty("--sf", newFactor.toString());
|
|
192
|
+
|
|
193
|
+
window.dispatchEvent(
|
|
194
|
+
new CustomEvent("scaling-changed", {
|
|
195
|
+
detail: { scalingFactor: newFactor, config },
|
|
196
|
+
})
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get the current scaling factor
|
|
202
|
+
* @returns The current scaling factor
|
|
203
|
+
*/
|
|
204
|
+
export function getScalingFactor(): number {
|
|
205
|
+
return scalingFactor.get();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Convert a design pixel value to scaled pixels
|
|
210
|
+
* @param designPx - The design pixel value (based on 280px width)
|
|
211
|
+
* @returns The scaled pixel value
|
|
212
|
+
*/
|
|
213
|
+
export function scale(designPx: number): number {
|
|
214
|
+
return designPx * scalingFactor.get();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Convert a scaled pixel value back to design pixels
|
|
219
|
+
* @param scaledPx - The scaled pixel value
|
|
220
|
+
* @returns The design pixel value
|
|
221
|
+
*/
|
|
222
|
+
export function unscale(scaledPx: number): number {
|
|
223
|
+
const factor = scalingFactor.get();
|
|
224
|
+
return factor === 0 ? scaledPx : scaledPx / factor;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ============================================================================
|
|
228
|
+
// Unified Initialization
|
|
229
|
+
// ============================================================================
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Initialize device detection and scaling
|
|
233
|
+
* Sets CSS classes (.mobile/.desktop) and --sf custom property
|
|
85
234
|
*/
|
|
86
235
|
export function initDeviceDetection(): DeviceInfo {
|
|
87
236
|
const deviceInfo = getDeviceInfo();
|
|
88
237
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const designWidth = 280;
|
|
93
|
-
const actualWidth = deviceInfo.screenWidth;
|
|
94
|
-
const scalingFactor = actualWidth / designWidth;
|
|
95
|
-
|
|
96
|
-
// Set CSS custom property for scaling on html element
|
|
97
|
-
document.documentElement.style.setProperty(
|
|
98
|
-
"--sf",
|
|
99
|
-
scalingFactor.toFixed(3)
|
|
100
|
-
);
|
|
101
|
-
// Also set --sf for backwards compatibility
|
|
102
|
-
document.documentElement.style.setProperty(
|
|
103
|
-
"--sf",
|
|
104
|
-
scalingFactor.toFixed(3)
|
|
105
|
-
);
|
|
238
|
+
if (typeof document === "undefined") {
|
|
239
|
+
return deviceInfo;
|
|
240
|
+
}
|
|
106
241
|
|
|
107
|
-
|
|
242
|
+
// Set device class on html element
|
|
243
|
+
if (deviceInfo.isMobile) {
|
|
108
244
|
document.documentElement.classList.add("mobile");
|
|
109
245
|
document.documentElement.classList.remove("desktop");
|
|
246
|
+
} else {
|
|
247
|
+
document.documentElement.classList.add("desktop");
|
|
248
|
+
document.documentElement.classList.remove("mobile");
|
|
249
|
+
}
|
|
110
250
|
|
|
251
|
+
// Update scaling factor (handles --sf CSS property)
|
|
252
|
+
updateScalingFactor();
|
|
253
|
+
|
|
254
|
+
// Log device info
|
|
255
|
+
const factor = scalingFactor.get();
|
|
256
|
+
if (deviceInfo.isMobile) {
|
|
111
257
|
console.log(
|
|
112
|
-
`[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${
|
|
258
|
+
`[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${factor.toFixed(2)}`
|
|
113
259
|
);
|
|
114
260
|
} else {
|
|
115
|
-
// Desktop - no scaling
|
|
116
|
-
if (typeof document !== "undefined") {
|
|
117
|
-
document.documentElement.style.setProperty("--sf", "1");
|
|
118
|
-
// Also set --sf for backwards compatibility
|
|
119
|
-
document.documentElement.style.setProperty("--sf", "1");
|
|
120
|
-
|
|
121
|
-
// Add .desktop class and remove .mobile class
|
|
122
|
-
document.documentElement.classList.add("desktop");
|
|
123
|
-
document.documentElement.classList.remove("mobile");
|
|
124
|
-
}
|
|
125
261
|
console.log(
|
|
126
262
|
`[DS one] Desktop device detected (${deviceInfo.screenWidth}x${deviceInfo.screenHeight})`
|
|
127
263
|
);
|
|
@@ -136,6 +272,7 @@ export function initDeviceDetection(): DeviceInfo {
|
|
|
136
272
|
isDesktop: deviceInfo.isDesktop,
|
|
137
273
|
isTouchCapable: deviceInfo.isTouchCapable,
|
|
138
274
|
viewport: `${deviceInfo.screenWidth}x${deviceInfo.screenHeight}`,
|
|
275
|
+
scalingFactor: factor,
|
|
139
276
|
userAgent: deviceInfo.userAgent,
|
|
140
277
|
});
|
|
141
278
|
}
|
|
@@ -155,16 +292,25 @@ if (typeof window !== "undefined") {
|
|
|
155
292
|
initDeviceDetection();
|
|
156
293
|
}
|
|
157
294
|
|
|
158
|
-
//
|
|
159
|
-
let resizeTimeout:
|
|
295
|
+
// Single debounced resize handler for both device detection + scaling
|
|
296
|
+
let resizeTimeout: ReturnType<typeof setTimeout>;
|
|
160
297
|
window.addEventListener("resize", () => {
|
|
161
298
|
clearTimeout(resizeTimeout);
|
|
162
299
|
resizeTimeout = setTimeout(() => {
|
|
163
300
|
initDeviceDetection();
|
|
164
301
|
}, 100);
|
|
165
302
|
});
|
|
303
|
+
|
|
304
|
+
// Also handle orientation change
|
|
305
|
+
window.addEventListener("orientationchange", () => {
|
|
306
|
+
setTimeout(initDeviceDetection, 100);
|
|
307
|
+
});
|
|
166
308
|
}
|
|
167
309
|
|
|
310
|
+
// ============================================================================
|
|
311
|
+
// App-like Behavior
|
|
312
|
+
// ============================================================================
|
|
313
|
+
|
|
168
314
|
/**
|
|
169
315
|
* Disable double-tap to zoom in the browser (app-like behavior)
|
|
170
316
|
* Prevents all zoom gestures including double-tap and pinch-to-zoom
|
package/DS1/1-root/one.css
CHANGED
package/DS1/index.ts
CHANGED
|
@@ -23,7 +23,6 @@ export * from "./0-face/device";
|
|
|
23
23
|
export * from "./0-face/i18n";
|
|
24
24
|
export * from "./0-face/preferences";
|
|
25
25
|
export * from "./0-face/pricing";
|
|
26
|
-
export * from "./0-face/scaling";
|
|
27
26
|
export * from "./0-face/theme";
|
|
28
27
|
|
|
29
28
|
// ============================================================================
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# DS one (0.3.0-alpha.
|
|
1
|
+
# DS one (0.3.0-alpha.2)
|
|
2
2
|
|
|
3
3
|
A plug and play design system
|
|
4
4
|
|
|
@@ -20,7 +20,7 @@ yarn add ds-one@alpha
|
|
|
20
20
|
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
**Note**: Currently published as alpha version `0.3.0-alpha.
|
|
23
|
+
**Note**: Currently published as alpha version `0.3.0-alpha.2`
|
|
24
24
|
|
|
25
25
|
## Quick Start
|
|
26
26
|
|
package/dist/0-face/device.d.ts
CHANGED
|
@@ -9,6 +9,17 @@ export interface DeviceInfo {
|
|
|
9
9
|
screenWidth: number;
|
|
10
10
|
screenHeight: number;
|
|
11
11
|
}
|
|
12
|
+
export type ScalingMode = "auto" | "fixed" | "fluid";
|
|
13
|
+
export interface ScalingConfig {
|
|
14
|
+
mode: ScalingMode;
|
|
15
|
+
baseWidth: number;
|
|
16
|
+
minScale: number;
|
|
17
|
+
maxScale: number;
|
|
18
|
+
}
|
|
19
|
+
/** Reactive scaling factor signal */
|
|
20
|
+
export declare const scalingFactor: import("@lit-labs/signals").Signal.State<number>;
|
|
21
|
+
/** Current scaling configuration */
|
|
22
|
+
export declare const scalingConfig: import("@lit-labs/signals").Signal.State<ScalingConfig>;
|
|
12
23
|
/**
|
|
13
24
|
* Comprehensive mobile device detection
|
|
14
25
|
* Combines user agent detection, touch capability, and viewport size
|
|
@@ -19,7 +30,42 @@ export declare function detectMobileDevice(): boolean;
|
|
|
19
30
|
*/
|
|
20
31
|
export declare function getDeviceInfo(): DeviceInfo;
|
|
21
32
|
/**
|
|
22
|
-
*
|
|
33
|
+
* Calculate the scaling factor based on viewport width
|
|
34
|
+
* @param viewportWidth - Current viewport width in pixels
|
|
35
|
+
* @param config - Scaling configuration
|
|
36
|
+
* @returns The calculated scaling factor
|
|
37
|
+
*/
|
|
38
|
+
export declare function calculateScalingFactor(viewportWidth: number, config?: ScalingConfig): number;
|
|
39
|
+
/**
|
|
40
|
+
* Set the scaling configuration
|
|
41
|
+
* @param config - Partial scaling configuration to apply
|
|
42
|
+
*/
|
|
43
|
+
export declare function setScalingConfig(config: Partial<ScalingConfig>): void;
|
|
44
|
+
/**
|
|
45
|
+
* Update the scaling factor based on current viewport
|
|
46
|
+
* Desktop always uses factor 1; mobile uses computed factor
|
|
47
|
+
*/
|
|
48
|
+
export declare function updateScalingFactor(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Get the current scaling factor
|
|
51
|
+
* @returns The current scaling factor
|
|
52
|
+
*/
|
|
53
|
+
export declare function getScalingFactor(): number;
|
|
54
|
+
/**
|
|
55
|
+
* Convert a design pixel value to scaled pixels
|
|
56
|
+
* @param designPx - The design pixel value (based on 280px width)
|
|
57
|
+
* @returns The scaled pixel value
|
|
58
|
+
*/
|
|
59
|
+
export declare function scale(designPx: number): number;
|
|
60
|
+
/**
|
|
61
|
+
* Convert a scaled pixel value back to design pixels
|
|
62
|
+
* @param scaledPx - The scaled pixel value
|
|
63
|
+
* @returns The design pixel value
|
|
64
|
+
*/
|
|
65
|
+
export declare function unscale(scaledPx: number): number;
|
|
66
|
+
/**
|
|
67
|
+
* Initialize device detection and scaling
|
|
68
|
+
* Sets CSS classes (.mobile/.desktop) and --sf custom property
|
|
23
69
|
*/
|
|
24
70
|
export declare function initDeviceDetection(): DeviceInfo;
|
|
25
71
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../DS1/0-face/device.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../DS1/0-face/device.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAaD,qCAAqC;AACrC,eAAO,MAAM,aAAa,kDAAoB,CAAC;AAE/C,oCAAoC;AACpC,eAAO,MAAM,aAAa,yDAA8C,CAAC;AAMzE;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CA0B5C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,UAAU,CA6B1C;AAMD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,MAAM,GAAE,aAAmC,GAC1C,MAAM,CAYR;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CASrE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAiC1C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGhD;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CA8ChD;AAiCD;;;GAGG;AACH,wBAAgB,OAAO,IAAI,IAAI,CA4H9B"}
|
package/dist/0-face/device.js
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Device detection and
|
|
1
|
+
// device.ts
|
|
2
|
+
// Device detection, context utilities, and responsive scaling
|
|
3
|
+
import { signal } from "@lit-labs/signals";
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Configuration & Signals
|
|
6
|
+
// ============================================================================
|
|
7
|
+
const defaultScalingConfig = {
|
|
8
|
+
mode: "auto",
|
|
9
|
+
baseWidth: 280,
|
|
10
|
+
minScale: 0.75,
|
|
11
|
+
maxScale: 2.0,
|
|
12
|
+
};
|
|
13
|
+
/** Reactive scaling factor signal */
|
|
14
|
+
export const scalingFactor = signal(1);
|
|
15
|
+
/** Current scaling configuration */
|
|
16
|
+
export const scalingConfig = signal(defaultScalingConfig);
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Device Detection
|
|
19
|
+
// ============================================================================
|
|
3
20
|
/**
|
|
4
21
|
* Comprehensive mobile device detection
|
|
5
22
|
* Combines user agent detection, touch capability, and viewport size
|
|
@@ -50,36 +67,118 @@ export function getDeviceInfo() {
|
|
|
50
67
|
screenHeight,
|
|
51
68
|
};
|
|
52
69
|
}
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Scaling
|
|
72
|
+
// ============================================================================
|
|
53
73
|
/**
|
|
54
|
-
*
|
|
74
|
+
* Calculate the scaling factor based on viewport width
|
|
75
|
+
* @param viewportWidth - Current viewport width in pixels
|
|
76
|
+
* @param config - Scaling configuration
|
|
77
|
+
* @returns The calculated scaling factor
|
|
78
|
+
*/
|
|
79
|
+
export function calculateScalingFactor(viewportWidth, config = scalingConfig.get()) {
|
|
80
|
+
if (config.mode === "fixed") {
|
|
81
|
+
return 1;
|
|
82
|
+
}
|
|
83
|
+
const rawScale = viewportWidth / config.baseWidth;
|
|
84
|
+
const clampedScale = Math.max(config.minScale, Math.min(config.maxScale, rawScale));
|
|
85
|
+
return Number(clampedScale.toFixed(3));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Set the scaling configuration
|
|
89
|
+
* @param config - Partial scaling configuration to apply
|
|
90
|
+
*/
|
|
91
|
+
export function setScalingConfig(config) {
|
|
92
|
+
const currentConfig = scalingConfig.get();
|
|
93
|
+
const newConfig = { ...currentConfig, ...config };
|
|
94
|
+
scalingConfig.set(newConfig);
|
|
95
|
+
// Recalculate scaling factor if in browser
|
|
96
|
+
if (typeof window !== "undefined") {
|
|
97
|
+
updateScalingFactor();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Update the scaling factor based on current viewport
|
|
102
|
+
* Desktop always uses factor 1; mobile uses computed factor
|
|
103
|
+
*/
|
|
104
|
+
export function updateScalingFactor() {
|
|
105
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const isMobile = detectMobileDevice();
|
|
109
|
+
// Desktop: always use factor 1
|
|
110
|
+
if (!isMobile) {
|
|
111
|
+
const factor = 1;
|
|
112
|
+
scalingFactor.set(factor);
|
|
113
|
+
document.documentElement.style.setProperty("--sf", factor.toString());
|
|
114
|
+
window.dispatchEvent(new CustomEvent("scaling-changed", {
|
|
115
|
+
detail: { scalingFactor: factor, config: scalingConfig.get() },
|
|
116
|
+
}));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Mobile: compute scaling based on viewport
|
|
120
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
121
|
+
const config = scalingConfig.get();
|
|
122
|
+
const newFactor = calculateScalingFactor(viewportWidth, config);
|
|
123
|
+
scalingFactor.set(newFactor);
|
|
124
|
+
document.documentElement.style.setProperty("--sf", newFactor.toString());
|
|
125
|
+
window.dispatchEvent(new CustomEvent("scaling-changed", {
|
|
126
|
+
detail: { scalingFactor: newFactor, config },
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get the current scaling factor
|
|
131
|
+
* @returns The current scaling factor
|
|
132
|
+
*/
|
|
133
|
+
export function getScalingFactor() {
|
|
134
|
+
return scalingFactor.get();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Convert a design pixel value to scaled pixels
|
|
138
|
+
* @param designPx - The design pixel value (based on 280px width)
|
|
139
|
+
* @returns The scaled pixel value
|
|
140
|
+
*/
|
|
141
|
+
export function scale(designPx) {
|
|
142
|
+
return designPx * scalingFactor.get();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Convert a scaled pixel value back to design pixels
|
|
146
|
+
* @param scaledPx - The scaled pixel value
|
|
147
|
+
* @returns The design pixel value
|
|
148
|
+
*/
|
|
149
|
+
export function unscale(scaledPx) {
|
|
150
|
+
const factor = scalingFactor.get();
|
|
151
|
+
return factor === 0 ? scaledPx : scaledPx / factor;
|
|
152
|
+
}
|
|
153
|
+
// ============================================================================
|
|
154
|
+
// Unified Initialization
|
|
155
|
+
// ============================================================================
|
|
156
|
+
/**
|
|
157
|
+
* Initialize device detection and scaling
|
|
158
|
+
* Sets CSS classes (.mobile/.desktop) and --sf custom property
|
|
55
159
|
*/
|
|
56
160
|
export function initDeviceDetection() {
|
|
57
161
|
const deviceInfo = getDeviceInfo();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const scalingFactor = actualWidth / designWidth;
|
|
64
|
-
// Set CSS custom property for scaling on html element
|
|
65
|
-
document.documentElement.style.setProperty("--sf", scalingFactor.toFixed(3));
|
|
66
|
-
// Also set --sf for backwards compatibility
|
|
67
|
-
document.documentElement.style.setProperty("--sf", scalingFactor.toFixed(3));
|
|
68
|
-
// Add .mobile class to html element for CSS targeting
|
|
162
|
+
if (typeof document === "undefined") {
|
|
163
|
+
return deviceInfo;
|
|
164
|
+
}
|
|
165
|
+
// Set device class on html element
|
|
166
|
+
if (deviceInfo.isMobile) {
|
|
69
167
|
document.documentElement.classList.add("mobile");
|
|
70
168
|
document.documentElement.classList.remove("desktop");
|
|
71
|
-
console.log(`[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${scalingFactor.toFixed(2)}`);
|
|
72
169
|
}
|
|
73
170
|
else {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
171
|
+
document.documentElement.classList.add("desktop");
|
|
172
|
+
document.documentElement.classList.remove("mobile");
|
|
173
|
+
}
|
|
174
|
+
// Update scaling factor (handles --sf CSS property)
|
|
175
|
+
updateScalingFactor();
|
|
176
|
+
// Log device info
|
|
177
|
+
const factor = scalingFactor.get();
|
|
178
|
+
if (deviceInfo.isMobile) {
|
|
179
|
+
console.log(`[DS one] Mobile device detected - ${deviceInfo.deviceType} (${deviceInfo.screenWidth}x${deviceInfo.screenHeight}), scaling factor: ${factor.toFixed(2)}`);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
83
182
|
console.log(`[DS one] Desktop device detected (${deviceInfo.screenWidth}x${deviceInfo.screenHeight})`);
|
|
84
183
|
}
|
|
85
184
|
// Log additional details in development mode
|
|
@@ -91,6 +190,7 @@ export function initDeviceDetection() {
|
|
|
91
190
|
isDesktop: deviceInfo.isDesktop,
|
|
92
191
|
isTouchCapable: deviceInfo.isTouchCapable,
|
|
93
192
|
viewport: `${deviceInfo.screenWidth}x${deviceInfo.screenHeight}`,
|
|
193
|
+
scalingFactor: factor,
|
|
94
194
|
userAgent: deviceInfo.userAgent,
|
|
95
195
|
});
|
|
96
196
|
}
|
|
@@ -108,7 +208,7 @@ if (typeof window !== "undefined") {
|
|
|
108
208
|
// DOM is already ready
|
|
109
209
|
initDeviceDetection();
|
|
110
210
|
}
|
|
111
|
-
//
|
|
211
|
+
// Single debounced resize handler for both device detection + scaling
|
|
112
212
|
let resizeTimeout;
|
|
113
213
|
window.addEventListener("resize", () => {
|
|
114
214
|
clearTimeout(resizeTimeout);
|
|
@@ -116,7 +216,14 @@ if (typeof window !== "undefined") {
|
|
|
116
216
|
initDeviceDetection();
|
|
117
217
|
}, 100);
|
|
118
218
|
});
|
|
219
|
+
// Also handle orientation change
|
|
220
|
+
window.addEventListener("orientationchange", () => {
|
|
221
|
+
setTimeout(initDeviceDetection, 100);
|
|
222
|
+
});
|
|
119
223
|
}
|
|
224
|
+
// ============================================================================
|
|
225
|
+
// App-like Behavior
|
|
226
|
+
// ============================================================================
|
|
120
227
|
/**
|
|
121
228
|
* Disable double-tap to zoom in the browser (app-like behavior)
|
|
122
229
|
* Prevents all zoom gestures including double-tap and pinch-to-zoom
|