@screenly/edge-apps 0.0.1 → 0.0.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.
- package/dist/assets/fonts/Inter-Medium.woff2 +0 -0
- package/dist/assets/fonts/Inter-Regular.woff2 +0 -0
- package/dist/assets/fonts/Inter-SemiBold.woff2 +0 -0
- package/dist/assets/images/icons/chancesleet.svg +4 -0
- package/dist/assets/images/icons/clear-night.svg +5 -0
- package/dist/assets/images/icons/clear.svg +11 -0
- package/dist/assets/images/icons/cloudy.svg +4 -0
- package/dist/assets/images/icons/drizzle.svg +5 -0
- package/dist/assets/images/icons/fewdrops.svg +4 -0
- package/dist/assets/images/icons/fog.svg +6 -0
- package/dist/assets/images/icons/haze.svg +6 -0
- package/dist/assets/images/icons/mostly-cloudy-night.svg +7 -0
- package/dist/assets/images/icons/mostly-cloudy.svg +13 -0
- package/dist/assets/images/icons/partially-cloudy-night.svg +6 -0
- package/dist/assets/images/icons/partially-cloudy.svg +12 -0
- package/dist/assets/images/icons/partlysunny.svg +6 -0
- package/dist/assets/images/icons/rain-night.svg +8 -0
- package/dist/assets/images/icons/rainy.svg +6 -0
- package/dist/assets/images/icons/sleet-night.svg +14 -0
- package/dist/assets/images/icons/sleet.svg +4 -0
- package/dist/assets/images/icons/snow.svg +19 -0
- package/dist/assets/images/icons/thunderstorm-night.svg +9 -0
- package/dist/assets/images/icons/thunderstorm.svg +7 -0
- package/dist/assets/images/icons/windy.svg +6 -0
- package/dist/assets/images/screenly.svg +10 -0
- package/dist/components/app-header/app-header.d.ts +43 -0
- package/dist/components/app-header/app-header.d.ts.map +1 -0
- package/dist/components/app-header/app-header.js +244 -0
- package/dist/components/auto-scaler/auto-scaler.d.ts +65 -0
- package/dist/components/auto-scaler/auto-scaler.d.ts.map +1 -0
- package/dist/components/auto-scaler/auto-scaler.js +304 -0
- package/dist/components/brand-logo/brand-logo.d.ts +42 -0
- package/dist/components/brand-logo/brand-logo.d.ts.map +1 -0
- package/dist/components/brand-logo/brand-logo.js +209 -0
- package/dist/components/calendar-views/calendar-view-utils.d.ts +5 -0
- package/dist/components/calendar-views/calendar-view-utils.d.ts.map +1 -0
- package/dist/components/calendar-views/calendar-view-utils.js +73 -0
- package/dist/components/calendar-views/calendar-window-utils.d.ts +9 -0
- package/dist/components/calendar-views/calendar-window-utils.d.ts.map +1 -0
- package/dist/components/calendar-views/calendar-window-utils.js +57 -0
- package/dist/components/calendar-views/daily-calendar-view/daily-calendar-view-styles.d.ts +2 -0
- package/dist/components/calendar-views/daily-calendar-view/daily-calendar-view-styles.d.ts.map +1 -0
- package/dist/components/calendar-views/daily-calendar-view/daily-calendar-view-styles.js +175 -0
- package/dist/components/calendar-views/daily-calendar-view/daily-calendar-view.d.ts +21 -0
- package/dist/components/calendar-views/daily-calendar-view/daily-calendar-view.d.ts.map +1 -0
- package/dist/components/calendar-views/daily-calendar-view/daily-calendar-view.js +130 -0
- package/dist/components/calendar-views/daily-calendar-view/index.d.ts +2 -0
- package/dist/components/calendar-views/daily-calendar-view/index.d.ts.map +1 -0
- package/dist/components/calendar-views/daily-calendar-view/index.js +1 -0
- package/dist/components/calendar-views/event-layout.d.ts +18 -0
- package/dist/components/calendar-views/event-layout.d.ts.map +1 -0
- package/dist/components/calendar-views/event-layout.js +139 -0
- package/dist/components/calendar-views/schedule-calendar-view/index.d.ts +2 -0
- package/dist/components/calendar-views/schedule-calendar-view/index.d.ts.map +1 -0
- package/dist/components/calendar-views/schedule-calendar-view/index.js +1 -0
- package/dist/components/calendar-views/schedule-calendar-view/schedule-calendar-view-styles.d.ts +2 -0
- package/dist/components/calendar-views/schedule-calendar-view/schedule-calendar-view-styles.d.ts.map +1 -0
- package/dist/components/calendar-views/schedule-calendar-view/schedule-calendar-view-styles.js +118 -0
- package/dist/components/calendar-views/schedule-calendar-view/schedule-calendar-view.d.ts +23 -0
- package/dist/components/calendar-views/schedule-calendar-view/schedule-calendar-view.d.ts.map +1 -0
- package/dist/components/calendar-views/schedule-calendar-view/schedule-calendar-view.js +167 -0
- package/dist/components/calendar-views/weekly-calendar-view/index.d.ts +3 -0
- package/dist/components/calendar-views/weekly-calendar-view/index.d.ts.map +1 -0
- package/dist/components/calendar-views/weekly-calendar-view/index.js +1 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view-styles.d.ts +2 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view-styles.d.ts.map +1 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view-styles.js +234 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view-utils.d.ts +16 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view-utils.d.ts.map +1 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view-utils.js +83 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view.d.ts +26 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view.d.ts.map +1 -0
- package/dist/components/calendar-views/weekly-calendar-view/weekly-calendar-view.js +220 -0
- package/dist/components/dev-tools/dev-tools.d.ts +48 -0
- package/dist/components/dev-tools/dev-tools.d.ts.map +1 -0
- package/dist/components/dev-tools/dev-tools.js +186 -0
- package/dist/components/index.d.ts +14 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +13 -0
- package/dist/components/register.d.ts +12 -0
- package/dist/components/register.d.ts.map +1 -0
- package/dist/components/register.js +11 -0
- package/dist/core/index.d.ts +30 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +77 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/test/index.d.ts +3 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +2 -0
- package/dist/test/mock.d.ts +23 -0
- package/dist/test/mock.d.ts.map +1 -0
- package/dist/test/mock.js +49 -0
- package/dist/test/screenshots.d.ts +120 -0
- package/dist/test/screenshots.d.ts.map +1 -0
- package/dist/test/screenshots.js +127 -0
- package/dist/test/setup.d.ts +2 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/setup.js +13 -0
- package/dist/types/index.d.ts +138 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +15 -0
- package/dist/utils/calendar.d.ts +28 -0
- package/dist/utils/calendar.d.ts.map +1 -0
- package/dist/utils/calendar.js +77 -0
- package/dist/utils/error-handling.d.ts +6 -0
- package/dist/utils/error-handling.d.ts.map +1 -0
- package/dist/utils/error-handling.js +16 -0
- package/dist/utils/html.d.ts +7 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +13 -0
- package/dist/utils/index.d.ts +13 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +12 -0
- package/dist/utils/locale.d.ts +68 -0
- package/dist/utils/locale.d.ts.map +1 -0
- package/dist/utils/locale.js +318 -0
- package/dist/utils/metadata.d.ts +39 -0
- package/dist/utils/metadata.d.ts.map +1 -0
- package/dist/utils/metadata.js +66 -0
- package/dist/utils/oauth.d.ts +16 -0
- package/dist/utils/oauth.d.ts.map +1 -0
- package/dist/utils/oauth.js +42 -0
- package/dist/utils/screen.d.ts +26 -0
- package/dist/utils/screen.d.ts.map +1 -0
- package/dist/utils/screen.js +44 -0
- package/dist/utils/settings.d.ts +38 -0
- package/dist/utils/settings.d.ts.map +1 -0
- package/dist/utils/settings.js +89 -0
- package/dist/utils/template.d.ts +2 -0
- package/dist/utils/template.d.ts.map +1 -0
- package/dist/utils/template.js +6 -0
- package/dist/utils/theme.d.ts +47 -0
- package/dist/utils/theme.d.ts.map +1 -0
- package/dist/utils/theme.js +183 -0
- package/dist/utils/utm.d.ts +23 -0
- package/dist/utils/utm.d.ts.map +1 -0
- package/dist/utils/utm.js +30 -0
- package/dist/utils/weather.d.ts +84 -0
- package/dist/utils/weather.d.ts.map +1 -0
- package/dist/utils/weather.js +272 -0
- package/package.json +8 -7
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen Utilities
|
|
3
|
+
* Utilities for screen orientation, dimensions, and other screen-related functions
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check if the current screen orientation is portrait
|
|
7
|
+
* @returns true if portrait, false if landscape
|
|
8
|
+
*/
|
|
9
|
+
export function isPortrait() {
|
|
10
|
+
if (typeof window === 'undefined') {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return window.matchMedia('(orientation: portrait)').matches;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check if the current screen orientation is landscape
|
|
17
|
+
* @returns true if landscape, false if portrait
|
|
18
|
+
*/
|
|
19
|
+
export function isLandscape() {
|
|
20
|
+
if (typeof window === 'undefined') {
|
|
21
|
+
return true; // Default to landscape for SSR
|
|
22
|
+
}
|
|
23
|
+
return window.matchMedia('(orientation: landscape)').matches;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get the current screen orientation
|
|
27
|
+
* @returns 'portrait' | 'landscape'
|
|
28
|
+
*/
|
|
29
|
+
export function getOrientation() {
|
|
30
|
+
return isPortrait() ? 'portrait' : 'landscape';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Center the auto-scaler element vertically within the viewport.
|
|
34
|
+
* Useful for apps that restrict display to a single orientation (portrait or
|
|
35
|
+
* landscape), where the auto-scaler may not fill the full viewport height.
|
|
36
|
+
*/
|
|
37
|
+
export function centerAutoScalerVertically() {
|
|
38
|
+
const scaler = document.querySelector('auto-scaler');
|
|
39
|
+
if (!scaler)
|
|
40
|
+
return;
|
|
41
|
+
const scaledHeight = scaler.getBoundingClientRect().height;
|
|
42
|
+
const offsetY = Math.max(0, (window.innerHeight - scaledHeight) / 2);
|
|
43
|
+
scaler.style.top = `${offsetY}px`;
|
|
44
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ScreenlySettings } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get all Screenly settings
|
|
4
|
+
*/
|
|
5
|
+
export declare function getSettings(): ScreenlySettings;
|
|
6
|
+
/**
|
|
7
|
+
* Get a specific setting value
|
|
8
|
+
*/
|
|
9
|
+
export declare function getSetting<T = unknown>(key: string): T | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Get a setting with a default value
|
|
12
|
+
*/
|
|
13
|
+
export declare function getSettingWithDefault<T>(key: string, defaultValue: T): T;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a setting exists
|
|
16
|
+
*/
|
|
17
|
+
export declare function hasSetting(key: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Get the theme mode
|
|
20
|
+
*/
|
|
21
|
+
export declare function getTheme(): 'light' | 'dark' | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Get the CORS proxy URL
|
|
24
|
+
*/
|
|
25
|
+
export declare function getCorsProxyUrl(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Signal that the app is ready for rendering
|
|
28
|
+
* This should be called when your app has finished loading and is ready to be displayed
|
|
29
|
+
*/
|
|
30
|
+
export declare function signalReady(): void;
|
|
31
|
+
export type MeasurementUnit = 'metric' | 'imperial';
|
|
32
|
+
/**
|
|
33
|
+
* Resolve measurement unit from settings with auto-detection fallback
|
|
34
|
+
* @param countryCode - Two-character ISO country code for auto-detection
|
|
35
|
+
* @returns Resolved measurement unit ('metric' or 'imperial')
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveMeasurementUnit(countryCode: string): MeasurementUnit;
|
|
38
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/utils/settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAGzD;;GAEG;AACH,wBAAgB,WAAW,IAAI,gBAAgB,CAE9C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAElE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,CA0BxE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,GAAG,MAAM,GAAG,SAAS,CAEvD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAGD,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,UAAU,CAAA;AAEnD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAa3E"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getMeasurementUnitByCountry } from './locale.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get all Screenly settings
|
|
4
|
+
*/
|
|
5
|
+
export function getSettings() {
|
|
6
|
+
return screenly.settings;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Get a specific setting value
|
|
10
|
+
*/
|
|
11
|
+
export function getSetting(key) {
|
|
12
|
+
return screenly.settings[key];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get a setting with a default value
|
|
16
|
+
*/
|
|
17
|
+
export function getSettingWithDefault(key, defaultValue) {
|
|
18
|
+
const value = screenly.settings[key];
|
|
19
|
+
if (value === undefined)
|
|
20
|
+
return defaultValue;
|
|
21
|
+
if (typeof value === 'string' && value === '') {
|
|
22
|
+
return defaultValue;
|
|
23
|
+
}
|
|
24
|
+
// If the value is a string and the default is a number, try to parse it
|
|
25
|
+
if (typeof value === 'string' && typeof defaultValue === 'number') {
|
|
26
|
+
const trimmed = value.trim();
|
|
27
|
+
if (trimmed === '')
|
|
28
|
+
return defaultValue;
|
|
29
|
+
const parsed = Number(trimmed);
|
|
30
|
+
if (!isNaN(parsed))
|
|
31
|
+
return parsed;
|
|
32
|
+
return defaultValue;
|
|
33
|
+
}
|
|
34
|
+
// If the value is a string and the default is a boolean, try to parse it
|
|
35
|
+
if (typeof value === 'string' && typeof defaultValue === 'boolean') {
|
|
36
|
+
const lowerValue = value.toLowerCase();
|
|
37
|
+
if (lowerValue === 'true')
|
|
38
|
+
return true;
|
|
39
|
+
if (lowerValue === 'false')
|
|
40
|
+
return false;
|
|
41
|
+
return defaultValue;
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if a setting exists
|
|
47
|
+
*/
|
|
48
|
+
export function hasSetting(key) {
|
|
49
|
+
return key in screenly.settings;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the theme mode
|
|
53
|
+
*/
|
|
54
|
+
export function getTheme() {
|
|
55
|
+
return screenly.settings.theme;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the CORS proxy URL
|
|
59
|
+
*/
|
|
60
|
+
export function getCorsProxyUrl() {
|
|
61
|
+
return screenly.cors_proxy_url;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Signal that the app is ready for rendering
|
|
65
|
+
* This should be called when your app has finished loading and is ready to be displayed
|
|
66
|
+
*/
|
|
67
|
+
export function signalReady() {
|
|
68
|
+
screenly.signalReadyForRendering();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolve measurement unit from settings with auto-detection fallback
|
|
72
|
+
* @param countryCode - Two-character ISO country code for auto-detection
|
|
73
|
+
* @returns Resolved measurement unit ('metric' or 'imperial')
|
|
74
|
+
*/
|
|
75
|
+
export function resolveMeasurementUnit(countryCode) {
|
|
76
|
+
const unitSetting = getSettingWithDefault('unit', 'auto');
|
|
77
|
+
if (unitSetting === 'auto') {
|
|
78
|
+
// Auto-detect based on country when setting is explicitly 'auto'
|
|
79
|
+
return getMeasurementUnitByCountry(countryCode);
|
|
80
|
+
}
|
|
81
|
+
else if (unitSetting === 'metric' || unitSetting === 'imperial') {
|
|
82
|
+
// Only accept known valid units
|
|
83
|
+
return unitSetting;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Fallback for invalid/corrupted settings: auto-detect based on country
|
|
87
|
+
return getMeasurementUnitByCountry(countryCode);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/utils/template.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,mBAAmB,CAI3D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ThemeColors, BrandingConfig } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default theme colors used by Screenly
|
|
4
|
+
*/
|
|
5
|
+
export declare const DEFAULT_THEME_COLORS: ThemeColors;
|
|
6
|
+
/**
|
|
7
|
+
* Get the primary theme color from settings or use default
|
|
8
|
+
*/
|
|
9
|
+
export declare function getPrimaryColor(accentColor?: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get the secondary theme color based on theme mode
|
|
12
|
+
*/
|
|
13
|
+
export declare function getSecondaryColor(theme: 'light' | 'dark' | undefined, lightColor?: string, darkColor?: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Setup theme colors from Screenly settings
|
|
16
|
+
* This function reads from the global screenly object and returns theme colors
|
|
17
|
+
*/
|
|
18
|
+
export declare function getThemeColors(): ThemeColors;
|
|
19
|
+
/**
|
|
20
|
+
* Apply theme colors to CSS custom properties
|
|
21
|
+
*/
|
|
22
|
+
export declare function applyThemeColors(colors: ThemeColors): void;
|
|
23
|
+
/**
|
|
24
|
+
* Setup theme by reading from Screenly settings and applying to CSS
|
|
25
|
+
*/
|
|
26
|
+
export declare function setupTheme(): ThemeColors;
|
|
27
|
+
/**
|
|
28
|
+
* Fetch and process a logo image from a URL
|
|
29
|
+
* Handles SVG, PNG, and JPEG formats
|
|
30
|
+
*/
|
|
31
|
+
export declare function fetchLogoImage(fileUrl: string): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Setup branding logo from Screenly settings.
|
|
34
|
+
*
|
|
35
|
+
* Attempts to fetch the logo image using a CORS proxy URL based on the current theme.
|
|
36
|
+
* Falls back to a direct URL if the proxy fetch fails, and returns the default logo if no logo is configured or all fetch attempts fail.
|
|
37
|
+
*
|
|
38
|
+
* @returns {Promise<string>} The processed logo URL:
|
|
39
|
+
* - Returns a data URI for SVG images, or the original URL for PNG/JPEG images, if successfully fetched via the CORS proxy or fallback URL.
|
|
40
|
+
* - Returns the default logo URL if no logo is configured or all fetch attempts fail.
|
|
41
|
+
*/
|
|
42
|
+
export declare function setupBrandingLogo(): Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Setup complete branding (theme colors and logo)
|
|
45
|
+
*/
|
|
46
|
+
export declare function setupBranding(): Promise<BrandingConfig>;
|
|
47
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/utils/theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAGpE;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAKlC,CAAA;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,EACnC,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAgBR;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAgB5C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAiB1D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,WAAW,CAIxC;AAaD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkDrE;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAyCzD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC,CAQ7D"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import defaultLogoUrl from '../assets/images/screenly.svg';
|
|
2
|
+
/**
|
|
3
|
+
* Default theme colors used by Screenly
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_THEME_COLORS = {
|
|
6
|
+
primary: '#972EFF',
|
|
7
|
+
secondary: '#454BD2',
|
|
8
|
+
tertiary: '#FFFFFF',
|
|
9
|
+
background: '#C9CDD0',
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Get the primary theme color from settings or use default
|
|
13
|
+
*/
|
|
14
|
+
export function getPrimaryColor(accentColor) {
|
|
15
|
+
if (!accentColor || accentColor.toLowerCase() === '#ffffff') {
|
|
16
|
+
return DEFAULT_THEME_COLORS.primary;
|
|
17
|
+
}
|
|
18
|
+
return accentColor;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the secondary theme color based on theme mode
|
|
22
|
+
*/
|
|
23
|
+
export function getSecondaryColor(theme, lightColor, darkColor) {
|
|
24
|
+
const defaultSecondary = '#adafbe';
|
|
25
|
+
if (theme === 'light') {
|
|
26
|
+
return !lightColor || lightColor.toLowerCase() === '#ffffff'
|
|
27
|
+
? defaultSecondary
|
|
28
|
+
: lightColor;
|
|
29
|
+
}
|
|
30
|
+
if (theme === 'dark') {
|
|
31
|
+
return !darkColor || darkColor.toLowerCase() === '#ffffff'
|
|
32
|
+
? defaultSecondary
|
|
33
|
+
: darkColor;
|
|
34
|
+
}
|
|
35
|
+
return DEFAULT_THEME_COLORS.secondary;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Setup theme colors from Screenly settings
|
|
39
|
+
* This function reads from the global screenly object and returns theme colors
|
|
40
|
+
*/
|
|
41
|
+
export function getThemeColors() {
|
|
42
|
+
const settings = screenly.settings;
|
|
43
|
+
const primary = getPrimaryColor(settings.screenly_color_accent);
|
|
44
|
+
const secondary = getSecondaryColor(settings.theme, settings.screenly_color_light, settings.screenly_color_dark);
|
|
45
|
+
return {
|
|
46
|
+
primary,
|
|
47
|
+
secondary,
|
|
48
|
+
tertiary: DEFAULT_THEME_COLORS.tertiary,
|
|
49
|
+
background: DEFAULT_THEME_COLORS.background,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Apply theme colors to CSS custom properties
|
|
54
|
+
*/
|
|
55
|
+
export function applyThemeColors(colors) {
|
|
56
|
+
document.documentElement.style.setProperty('--theme-color-primary', colors.primary);
|
|
57
|
+
document.documentElement.style.setProperty('--theme-color-secondary', colors.secondary);
|
|
58
|
+
document.documentElement.style.setProperty('--theme-color-tertiary', colors.tertiary);
|
|
59
|
+
document.documentElement.style.setProperty('--theme-color-background', colors.background);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Setup theme by reading from Screenly settings and applying to CSS
|
|
63
|
+
*/
|
|
64
|
+
export function setupTheme() {
|
|
65
|
+
const colors = getThemeColors();
|
|
66
|
+
applyThemeColors(colors);
|
|
67
|
+
return colors;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Convert Uint8Array to base64 string
|
|
71
|
+
*/
|
|
72
|
+
function uint8ToBase64(bytes) {
|
|
73
|
+
let binary = '';
|
|
74
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
75
|
+
binary += String.fromCharCode(bytes[i]);
|
|
76
|
+
}
|
|
77
|
+
return btoa(binary);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Fetch and process a logo image from a URL
|
|
81
|
+
* Handles SVG, PNG, and JPEG formats
|
|
82
|
+
*/
|
|
83
|
+
export async function fetchLogoImage(fileUrl) {
|
|
84
|
+
const response = await fetch(fileUrl);
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
throw new Error(`Failed to fetch image from ${fileUrl}, status: ${response.status}`);
|
|
87
|
+
}
|
|
88
|
+
const blob = await response.blob();
|
|
89
|
+
const buffer = await blob.arrayBuffer();
|
|
90
|
+
const uintArray = new Uint8Array(buffer);
|
|
91
|
+
// Get the first 8 bytes for magic number detection (sufficient for PNG and JPEG)
|
|
92
|
+
const hex = Array.from(uintArray.slice(0, 8))
|
|
93
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
94
|
+
.join('')
|
|
95
|
+
.toUpperCase();
|
|
96
|
+
// Convert the first few bytes to ASCII for text-based formats like SVG
|
|
97
|
+
const ascii = String.fromCharCode(...Array.from(uintArray.slice(0, 100)));
|
|
98
|
+
const pngMagicNumber = '89504E470D0A1A0A';
|
|
99
|
+
const jpegMagicNumber = 'FFD8FF';
|
|
100
|
+
// Determine file type based on magic number or ASCII text
|
|
101
|
+
if (ascii.startsWith('<?xml') || ascii.startsWith('<svg')) {
|
|
102
|
+
// Convert SVG to Base64
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const svgReader = new FileReader();
|
|
105
|
+
svgReader.readAsText(blob);
|
|
106
|
+
svgReader.onloadend = function () {
|
|
107
|
+
try {
|
|
108
|
+
const svgText = svgReader.result;
|
|
109
|
+
const encoder = new TextEncoder();
|
|
110
|
+
const uint8Array = encoder.encode(svgText);
|
|
111
|
+
const base64 = uint8ToBase64(uint8Array);
|
|
112
|
+
resolve('data:image/svg+xml;base64,' + base64);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
reject(error);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
svgReader.onerror = () => reject(new Error('Failed to read SVG file'));
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (hex.startsWith(pngMagicNumber) || hex.startsWith(jpegMagicNumber)) {
|
|
122
|
+
// Return URL for PNG or JPEG
|
|
123
|
+
return fileUrl;
|
|
124
|
+
}
|
|
125
|
+
throw new Error('Unknown image type');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Setup branding logo from Screenly settings.
|
|
129
|
+
*
|
|
130
|
+
* Attempts to fetch the logo image using a CORS proxy URL based on the current theme.
|
|
131
|
+
* Falls back to a direct URL if the proxy fetch fails, and returns the default logo if no logo is configured or all fetch attempts fail.
|
|
132
|
+
*
|
|
133
|
+
* @returns {Promise<string>} The processed logo URL:
|
|
134
|
+
* - Returns a data URI for SVG images, or the original URL for PNG/JPEG images, if successfully fetched via the CORS proxy or fallback URL.
|
|
135
|
+
* - Returns the default logo URL if no logo is configured or all fetch attempts fail.
|
|
136
|
+
*/
|
|
137
|
+
export async function setupBrandingLogo() {
|
|
138
|
+
const settings = screenly.settings;
|
|
139
|
+
const theme = settings.theme || 'light';
|
|
140
|
+
const lightLogo = settings.screenly_logo_light ?? '';
|
|
141
|
+
const darkLogo = settings.screenly_logo_dark ?? '';
|
|
142
|
+
// Determine which logo to use based on theme
|
|
143
|
+
let logoUrl = '';
|
|
144
|
+
let fallbackUrl = '';
|
|
145
|
+
const isDark = theme === 'dark';
|
|
146
|
+
const primaryLogo = isDark ? darkLogo : lightLogo;
|
|
147
|
+
const secondaryLogo = isDark ? lightLogo : darkLogo;
|
|
148
|
+
const resolvedLogo = primaryLogo || secondaryLogo;
|
|
149
|
+
if (resolvedLogo) {
|
|
150
|
+
logoUrl = `${screenly.cors_proxy_url}/${resolvedLogo}`;
|
|
151
|
+
fallbackUrl = resolvedLogo;
|
|
152
|
+
}
|
|
153
|
+
// Return default logo if no logo is configured
|
|
154
|
+
if (!fallbackUrl)
|
|
155
|
+
return defaultLogoUrl;
|
|
156
|
+
// Try to fetch the image using the CORS proxy URL
|
|
157
|
+
try {
|
|
158
|
+
return await fetchLogoImage(logoUrl);
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
console.warn('Failed to fetch logo image from primary URL:', logoUrl, err);
|
|
162
|
+
}
|
|
163
|
+
// If CORS fails, try the fallback URL
|
|
164
|
+
try {
|
|
165
|
+
return await fetchLogoImage(fallbackUrl);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
console.warn('Failed to fetch logo image from fallback URL:', fallbackUrl, err);
|
|
169
|
+
}
|
|
170
|
+
// Return default logo if all fetches fail
|
|
171
|
+
return defaultLogoUrl;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Setup complete branding (theme colors and logo)
|
|
175
|
+
*/
|
|
176
|
+
export async function setupBranding() {
|
|
177
|
+
const colors = setupTheme();
|
|
178
|
+
const logoUrl = await setupBrandingLogo();
|
|
179
|
+
return {
|
|
180
|
+
colors,
|
|
181
|
+
logoUrl,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UTM parameters for tracking
|
|
3
|
+
*/
|
|
4
|
+
export interface UTMParams {
|
|
5
|
+
utm_source: string;
|
|
6
|
+
utm_medium: string;
|
|
7
|
+
utm_location: string;
|
|
8
|
+
utm_placement: string;
|
|
9
|
+
[key: string]: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get default UTM parameters from Screenly metadata
|
|
13
|
+
*/
|
|
14
|
+
export declare function getDefaultUTMParams(): UTMParams;
|
|
15
|
+
/**
|
|
16
|
+
* Add UTM parameters to a URL
|
|
17
|
+
*/
|
|
18
|
+
export declare function addUTMParams(url: string, params?: Partial<UTMParams>): string;
|
|
19
|
+
/**
|
|
20
|
+
* Conditionally add UTM parameters to a URL
|
|
21
|
+
*/
|
|
22
|
+
export declare function addUTMParamsIf(url: string, enabled: boolean, params?: Partial<UTMParams>): string;
|
|
23
|
+
//# sourceMappingURL=utm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utm.d.ts","sourceRoot":"","sources":["../../src/utils/utm.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CACtB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,SAAS,CAS/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,MAAM,CAU7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAC1B,MAAM,CAER"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get default UTM parameters from Screenly metadata
|
|
3
|
+
*/
|
|
4
|
+
export function getDefaultUTMParams() {
|
|
5
|
+
const { location, hostname } = screenly.metadata;
|
|
6
|
+
return {
|
|
7
|
+
utm_source: 'screenly',
|
|
8
|
+
utm_medium: 'digital-signage',
|
|
9
|
+
utm_location: location,
|
|
10
|
+
utm_placement: hostname,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Add UTM parameters to a URL
|
|
15
|
+
*/
|
|
16
|
+
export function addUTMParams(url, params) {
|
|
17
|
+
const utmParams = { ...getDefaultUTMParams(), ...params };
|
|
18
|
+
const queryString = Object.entries(utmParams)
|
|
19
|
+
.filter(([, value]) => value !== undefined)
|
|
20
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
|
21
|
+
.join('&');
|
|
22
|
+
const separator = url.includes('?') ? '&' : '?';
|
|
23
|
+
return `${url}${separator}${queryString}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Conditionally add UTM parameters to a URL
|
|
27
|
+
*/
|
|
28
|
+
export function addUTMParamsIf(url, enabled, params) {
|
|
29
|
+
return enabled ? addUTMParams(url, params) : url;
|
|
30
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weather Utilities
|
|
3
|
+
* Functions for weather icon mapping and related utilities
|
|
4
|
+
*/
|
|
5
|
+
import { type MeasurementUnit } from './settings.js';
|
|
6
|
+
export declare const WEATHER_ICONS: Record<string, string>;
|
|
7
|
+
/**
|
|
8
|
+
* Check if a given timestamp is during nighttime (8 PM - 5 AM) in the specified timezone
|
|
9
|
+
*/
|
|
10
|
+
export declare function isNightForTimestamp(dt: number, timeZone: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Get weather icon key based on OpenWeatherMap weather condition ID and time of day
|
|
13
|
+
* @param id - OpenWeatherMap weather condition ID (e.g., 800 for clear sky)
|
|
14
|
+
* @param dt - Unix timestamp in seconds
|
|
15
|
+
* @param timeZone - IANA timezone string (e.g., 'America/New_York')
|
|
16
|
+
* @returns Icon key string (e.g., 'clear', 'clear-night', 'rain', etc.)
|
|
17
|
+
*/
|
|
18
|
+
export declare function getWeatherIconKey(id: number, dt: number, timeZone: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Get the full URL path for a weather icon
|
|
21
|
+
* @param iconKey - Icon key from getWeatherIconKey (e.g., 'clear', 'rain-night')
|
|
22
|
+
* @param iconBase - Base path for weather icons (default: '/assets/images/icons')
|
|
23
|
+
* @returns Full URL path to the icon SVG file
|
|
24
|
+
*/
|
|
25
|
+
export declare function getWeatherIconUrl(iconKey: string, iconBase?: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Get weather icon source (imported SVG) based on weather condition ID and time
|
|
28
|
+
* @param weatherId - OpenWeatherMap weather condition ID (e.g., 800 for clear sky)
|
|
29
|
+
* @param dt - Unix timestamp in seconds
|
|
30
|
+
* @param timeZone - IANA timezone string (e.g., 'America/New_York')
|
|
31
|
+
* @returns Icon source string (Vite-imported SVG path)
|
|
32
|
+
*/
|
|
33
|
+
export declare function getWeatherIcon(weatherId: number, dt: number, timeZone: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Validate OpenWeatherMap API response
|
|
36
|
+
* Note: `cod` can be number (200) or string ("200") depending on the endpoint
|
|
37
|
+
*/
|
|
38
|
+
export declare function isValidWeatherResponse(data: {
|
|
39
|
+
cod?: number | string;
|
|
40
|
+
main?: {
|
|
41
|
+
temp?: number;
|
|
42
|
+
};
|
|
43
|
+
}): boolean;
|
|
44
|
+
export interface CurrentWeatherRawData {
|
|
45
|
+
temperature: number;
|
|
46
|
+
tempHigh: number;
|
|
47
|
+
tempLow: number;
|
|
48
|
+
weatherId: number;
|
|
49
|
+
description: string;
|
|
50
|
+
iconSrc: string;
|
|
51
|
+
iconAlt: string;
|
|
52
|
+
unit: MeasurementUnit;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Fetch current weather data from OpenWeatherMap API
|
|
56
|
+
* Returns raw weather data that each app can map to its own interface
|
|
57
|
+
* @param lat - Latitude
|
|
58
|
+
* @param lng - Longitude
|
|
59
|
+
* @param tz - Timezone
|
|
60
|
+
* @param unit - Measurement unit ('metric' or 'imperial')
|
|
61
|
+
*/
|
|
62
|
+
export declare function fetchCurrentWeatherData(lat: number, lng: number, tz: string, unit?: MeasurementUnit): Promise<CurrentWeatherRawData | null>;
|
|
63
|
+
/**
|
|
64
|
+
* City information from reverse geocoding
|
|
65
|
+
*/
|
|
66
|
+
export interface CityInfo {
|
|
67
|
+
cityName: string;
|
|
68
|
+
countryCode: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get city information including name and country code from OpenWeatherMap reverse geocoding
|
|
72
|
+
* @param lat - Latitude
|
|
73
|
+
* @param lng - Longitude
|
|
74
|
+
* @returns Object containing cityName and countryCode
|
|
75
|
+
*/
|
|
76
|
+
export declare function getCityInfo(lat: number, lng: number): Promise<CityInfo>;
|
|
77
|
+
/**
|
|
78
|
+
* Get city name from coordinates using OpenWeatherMap reverse geocoding
|
|
79
|
+
* @param lat - Latitude
|
|
80
|
+
* @param lng - Longitude
|
|
81
|
+
* @returns City name in format "City, Country" or fallback location
|
|
82
|
+
*/
|
|
83
|
+
export declare function getCityName(lat: number, lng: number): Promise<string>;
|
|
84
|
+
//# sourceMappingURL=weather.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weather.d.ts","sourceRoot":"","sources":["../../src/utils/weather.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AA2BhE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuBhD,CAAA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CASzE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,GACf,MAAM,CAgCR;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAA+B,GACxC,MAAM,CA0BR;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,GACf,MAAM,CAGR;AAID;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACzB,GAAG,OAAO,CAOV;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,eAAe,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,eAA0B,GAC/B,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CA8DvC;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+C7E;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG3E"}
|