server-time-timer-yolabs-ui 1.0.0

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/README.md ADDED
@@ -0,0 +1,172 @@
1
+ Perfect! Here’s a **professional README** for your `server-time-timer-ui` package, fully detailed for enterprise usage:
2
+
3
+ ---
4
+
5
+ # ⏱️ server-time-timer-ui
6
+
7
+ **Enterprise-grade server-synchronized countdown timer UI for React and Next.js**
8
+ Designed for **consistent countdown across all devices**, with optional **customization, layouts, and progress display**.
9
+
10
+ ---
11
+
12
+ ## 🚀 Key Features
13
+
14
+ * 🔒 **Server time is the single source of truth** (uses `server-time-timer-yoLabs`)
15
+ * 🌍 Same countdown across **all platforms**
16
+ * 🧩 **Dynamic sizes**: `sm`, `md`, `lg`
17
+ * 🖌️ **Custom themes and colors**: light, dark, brand, or custom colors
18
+ * ⚡ Optional **progress bar**
19
+ * 🕒 Optional **unit display**: days, hours, minutes, seconds
20
+ * 🏢 **Enterprise-ready, React / Next.js / Telegram Mini Apps compatible**
21
+
22
+ ---
23
+
24
+ ## 📦 Installation
25
+
26
+ ```bash
27
+ npm install server-time-timer-ui server-time-timer-yoLabs
28
+ ```
29
+
30
+ or
31
+
32
+ ```bash
33
+ yarn add server-time-timer-ui server-time-timer-yoLabs
34
+ ```
35
+
36
+ ---
37
+
38
+ ## 🧠 How It Works
39
+
40
+ 1️⃣ Server sends the **current time** (`serverNow`)
41
+ 2️⃣ Client calculates **offset**
42
+ 3️⃣ Countdown runs locally using offset
43
+ 4️⃣ Optional **re-sync** keeps everything accurate
44
+
45
+ ✅ Result: perfect synchronized countdown across devices.
46
+
47
+ ---
48
+
49
+ ## 🔧 Props / Options
50
+
51
+ ```ts
52
+ export interface ServerTimerUIProps {
53
+ serverNow: string; // Current server time (UTC)
54
+ endTime: string; // Countdown target time (UTC)
55
+ size?: 'sm' | 'md' | 'lg'; // Default: 'md'
56
+ layout?: 'horizontal' | 'vertical' | 'compact'; // Default: 'horizontal'
57
+ theme?: 'light' | 'dark' | 'brand'; // Default: 'light'
58
+ showProgress?: boolean; // Show progress bar, default true
59
+ onEnd?: () => void; // Callback when countdown ends
60
+ className?: string; // Optional wrapper className
61
+ customColors?: { // Optional colors
62
+ background?: string;
63
+ text?: string;
64
+ unitBackground?: string;
65
+ progress?: string;
66
+ };
67
+ showUnits?: { // Optional unit display
68
+ days?: boolean;
69
+ hours?: boolean;
70
+ minutes?: boolean;
71
+ seconds?: boolean;
72
+ };
73
+ }
74
+ ```
75
+
76
+ ---
77
+
78
+ ## 🔧 Basic Usage
79
+
80
+ ```tsx
81
+ import React from 'react';
82
+ import { ServerTimerUI } from 'server-time-timer-ui';
83
+
84
+ export default function App() {
85
+ return (
86
+ <ServerTimerUI
87
+ serverNow="2025-12-25T12:00:00Z"
88
+ endTime="2025-12-25T12:10:00Z"
89
+ size="lg"
90
+ theme="brand"
91
+ showProgress={true}
92
+ customColors={{
93
+ background: '#fef9f3',
94
+ text: '#323130',
95
+ unitBackground: '#fffbdd',
96
+ progress: '#0078d4'
97
+ }}
98
+ showUnits={{ days: false, hours: true, minutes: true, seconds: true }}
99
+ onEnd={() => alert('Time is up!')}
100
+ />
101
+ );
102
+ }
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 🎨 Layouts
108
+
109
+ * **Horizontal (default)**: Units aligned in a row
110
+ * **Vertical**: Units stacked in a column
111
+ * **Compact**: Smaller units for tight spaces
112
+
113
+ ```tsx
114
+ <ServerTimerUI layout="vertical" />
115
+ <ServerTimerUI layout="compact" />
116
+ ```
117
+
118
+ ---
119
+
120
+ ## ⚡ Custom Colors
121
+
122
+ ```tsx
123
+ customColors={{
124
+ background: '#fff8f0',
125
+ text: '#333',
126
+ unitBackground: '#ffe5b4',
127
+ progress: '#0078d4'
128
+ }}
129
+ ```
130
+
131
+ ✅ Fully optional; uses theme defaults if not provided.
132
+
133
+ ---
134
+
135
+ ## 🕒 Optional Units
136
+
137
+ ```tsx
138
+ showUnits={{ days: false, hours: true, minutes: true, seconds: true }}
139
+ ```
140
+
141
+ ✅ Hide days, hours, minutes, or seconds dynamically based on UI needs.
142
+
143
+ ---
144
+
145
+ ## 🔁 Resync (Recommended for long timers)
146
+
147
+ ```ts
148
+ setInterval(async () => {
149
+ const res = await fetch('/api/server-time');
150
+ const data = await res.json();
151
+ timer.sync(data.now);
152
+ }, 30000);
153
+ ```
154
+
155
+ ---
156
+
157
+ ## 🏢 Use Cases
158
+
159
+ * 🎟️ Lottery & raffle countdowns
160
+ * 🛒 Flash sales & limited offers
161
+ * 📝 Online exams
162
+ * 🎮 Games & event timers
163
+ * 📱 Telegram Mini Apps
164
+ * 🌐 Distributed systems
165
+
166
+ ---
167
+
168
+ ## 📜 License
169
+
170
+ YonasLabs
171
+
172
+ ---
@@ -0,0 +1,12 @@
1
+ export declare function useServerTimer({ serverNow, endTime, onEnd }: {
2
+ serverNow: string;
3
+ endTime: string;
4
+ onEnd?: () => void;
5
+ }): {
6
+ days: number;
7
+ hours: number;
8
+ minutes: number;
9
+ seconds: number;
10
+ totalMs: number;
11
+ progress: number;
12
+ };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useServerTimer = useServerTimer;
4
+ const react_1 = require("react");
5
+ const server_time_timer_yoLabs_1 = require("server-time-timer-yoLabs");
6
+ function useServerTimer({ serverNow, endTime, onEnd }) {
7
+ const [time, setTime] = (0, react_1.useState)({
8
+ days: 0,
9
+ hours: 0,
10
+ minutes: 0,
11
+ seconds: 0,
12
+ totalMs: 0,
13
+ progress: 100
14
+ });
15
+ (0, react_1.useEffect)(() => {
16
+ const timer = (0, server_time_timer_yoLabs_1.createServerTimer)({ serverNow, endTime });
17
+ timer.onTick((t) => {
18
+ const totalDuration = new Date(endTime).getTime() - new Date(serverNow).getTime();
19
+ setTime({
20
+ days: t.days,
21
+ hours: t.hours,
22
+ minutes: t.minutes,
23
+ seconds: t.seconds,
24
+ totalMs: t.totalMs,
25
+ progress: Math.max(0, (t.totalMs / totalDuration) * 100)
26
+ });
27
+ if (t.totalMs <= 0 && onEnd)
28
+ onEnd();
29
+ });
30
+ timer.start();
31
+ return () => timer.stop();
32
+ }, [serverNow, endTime, onEnd]);
33
+ return time;
34
+ }
@@ -0,0 +1,2 @@
1
+ export { ServerTimerUI } from './ui/ServerTimerUI';
2
+ export type { ServerTimerUIProps } from './ui/types';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServerTimerUI = void 0;
4
+ var ServerTimerUI_1 = require("./ui/ServerTimerUI");
5
+ Object.defineProperty(exports, "ServerTimerUI", { enumerable: true, get: function () { return ServerTimerUI_1.ServerTimerUI; } });
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { ServerTimerUIProps } from './types';
3
+ export declare const ServerTimerUI: React.FC<ServerTimerUIProps>;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ServerTimerUI = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const TimerContainer_1 = __importDefault(require("./components/TimerContainer"));
9
+ const TimerUnit_1 = __importDefault(require("./components/TimerUnit"));
10
+ const TimerProgress_1 = __importDefault(require("./components/TimerProgress"));
11
+ const useServerTimer_1 = require("../hooks/useServerTimer");
12
+ const ServerTimerUI = ({ serverNow, endTime, size = 'md', theme = 'light', layout = 'horizontal', showProgress = true, customColors, showUnits = { days: true, hours: true, minutes: true, seconds: true }, onEnd }) => {
13
+ const time = (0, useServerTimer_1.useServerTimer)({ serverNow, endTime, onEnd });
14
+ return ((0, jsx_runtime_1.jsxs)(TimerContainer_1.default, { size: size, background: customColors === null || customColors === void 0 ? void 0 : customColors.background, color: customColors === null || customColors === void 0 ? void 0 : customColors.text, children: [showUnits.days && (0, jsx_runtime_1.jsx)(TimerUnit_1.default, { label: "Days", value: time.days, size: size, background: customColors === null || customColors === void 0 ? void 0 : customColors.unitBackground }), showUnits.hours && (0, jsx_runtime_1.jsx)(TimerUnit_1.default, { label: "Hours", value: time.hours, size: size, background: customColors === null || customColors === void 0 ? void 0 : customColors.unitBackground }), showUnits.minutes && (0, jsx_runtime_1.jsx)(TimerUnit_1.default, { label: "Minutes", value: time.minutes, size: size, background: customColors === null || customColors === void 0 ? void 0 : customColors.unitBackground }), showUnits.seconds && (0, jsx_runtime_1.jsx)(TimerUnit_1.default, { label: "Seconds", value: time.seconds, size: size, background: customColors === null || customColors === void 0 ? void 0 : customColors.unitBackground }), showProgress && (0, jsx_runtime_1.jsx)(TimerProgress_1.default, { value: time.progress, color: customColors === null || customColors === void 0 ? void 0 : customColors.progress })] }));
15
+ };
16
+ exports.ServerTimerUI = ServerTimerUI;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { TimerSize } from '../types';
3
+ interface TimerContainerProps {
4
+ children: React.ReactNode;
5
+ size?: TimerSize;
6
+ className?: string;
7
+ background?: string;
8
+ color?: string;
9
+ }
10
+ declare const TimerContainer: React.FC<TimerContainerProps>;
11
+ export default TimerContainer;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const paddingMap = {
5
+ sm: '0.5rem 1rem',
6
+ md: '1rem 1.5rem',
7
+ lg: '1.5rem 2rem'
8
+ };
9
+ const TimerContainer = ({ children, size = 'md', className, background = '#ffffff', color = '#323130' }) => ((0, jsx_runtime_1.jsx)("div", { className: className, style: {
10
+ backgroundColor: background,
11
+ color,
12
+ border: '1px solid #e1e1e1',
13
+ borderRadius: '4px',
14
+ boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
15
+ padding: paddingMap[size],
16
+ display: 'inline-flex',
17
+ alignItems: 'center',
18
+ gap: '0.75rem',
19
+ fontFamily: `'Segoe UI', sans-serif`,
20
+ fontSize: '1rem'
21
+ }, children: children }));
22
+ exports.default = TimerContainer;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const TimerFinished: React.FC;
3
+ export default TimerFinished;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const TimerFinished = () => ((0, jsx_runtime_1.jsx)("div", { style: {
5
+ padding: '0.75rem 1rem',
6
+ backgroundColor: '#f8d7da',
7
+ color: '#a4262c',
8
+ borderRadius: '4px',
9
+ fontWeight: 600,
10
+ fontFamily: `'Segoe UI', sans-serif`,
11
+ textAlign: 'center'
12
+ }, children: "\u23F0 Time\u2019s up!" }));
13
+ exports.default = TimerFinished;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface TimerProgressProps {
3
+ value: number;
4
+ color?: string;
5
+ }
6
+ declare const TimerProgress: React.FC<TimerProgressProps>;
7
+ export default TimerProgress;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const TimerProgress = ({ value, color = '#0078d4' }) => ((0, jsx_runtime_1.jsx)("div", { style: {
5
+ flex: 1,
6
+ height: '6px',
7
+ background: '#e1e1e1',
8
+ borderRadius: '3px',
9
+ overflow: 'hidden',
10
+ marginLeft: '0.5rem'
11
+ }, children: (0, jsx_runtime_1.jsx)("div", { style: {
12
+ width: `${value}%`,
13
+ background: color,
14
+ height: '100%'
15
+ } }) }));
16
+ exports.default = TimerProgress;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { TimerSize } from '../types';
3
+ export interface TimerUnitProps {
4
+ label: string;
5
+ value: number;
6
+ size?: TimerSize;
7
+ background?: string;
8
+ color?: string;
9
+ }
10
+ declare const TimerUnit: React.FC<TimerUnitProps>;
11
+ export default TimerUnit;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const paddingMap = {
5
+ sm: '0.25rem 0.5rem',
6
+ md: '0.5rem 1rem',
7
+ lg: '0.75rem 1.5rem'
8
+ };
9
+ const fontSizeMap = {
10
+ sm: '0.625rem',
11
+ md: '0.75rem',
12
+ lg: '0.875rem'
13
+ };
14
+ const TimerUnit = ({ label, value, size = 'md', background = '#f3f2f1', color = '#323130' }) => ((0, jsx_runtime_1.jsxs)("div", { style: {
15
+ backgroundColor: background,
16
+ color,
17
+ borderRadius: '4px',
18
+ padding: paddingMap[size],
19
+ minWidth: '2.5rem',
20
+ textAlign: 'center'
21
+ }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontWeight: 600, fontSize: fontSizeMap[size] }, children: String(value).padStart(2, '0') }), (0, jsx_runtime_1.jsx)("div", { style: { fontSize: fontSizeMap[size], opacity: 0.8 }, children: label })] }));
22
+ exports.default = TimerUnit;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export declare const CompactLayout: React.FC<{
3
+ children: React.ReactNode;
4
+ }>;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CompactLayout = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const CompactLayout = ({ children }) => ((0, jsx_runtime_1.jsx)("div", { style: { display: 'inline-flex', gap: '0.25rem', fontSize: '0.875rem' }, children: children }));
6
+ exports.CompactLayout = CompactLayout;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export declare const HorizontalLayout: React.FC<{
3
+ children: React.ReactNode;
4
+ }>;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HorizontalLayout = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const HorizontalLayout = ({ children }) => ((0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', gap: '0.5rem' }, children: children }));
6
+ exports.HorizontalLayout = HorizontalLayout;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export declare const VerticalLayout: React.FC<{
3
+ children: React.ReactNode;
4
+ }>;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VerticalLayout = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const VerticalLayout = ({ children }) => ((0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', flexDirection: 'column', gap: '0.25rem' }, children: children }));
6
+ exports.VerticalLayout = VerticalLayout;
@@ -0,0 +1,4 @@
1
+ export declare const brand: {
2
+ background: string;
3
+ color: string;
4
+ };
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.brand = void 0;
4
+ exports.brand = { background: '#0078d4', color: '#ffffff' };
@@ -0,0 +1,4 @@
1
+ export declare const dark: {
2
+ background: string;
3
+ color: string;
4
+ };
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dark = void 0;
4
+ exports.dark = { background: '#323130', color: '#f3f2f1' };
@@ -0,0 +1,4 @@
1
+ export declare const light: {
2
+ background: string;
3
+ color: string;
4
+ };
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.light = void 0;
4
+ exports.light = { background: '#f3f2f1', color: '#323130' };
@@ -0,0 +1,25 @@
1
+ export type TimerSize = 'sm' | 'md' | 'lg';
2
+ export type TimerLayout = 'horizontal' | 'vertical' | 'compact';
3
+ export type TimerTheme = 'light' | 'dark' | 'brand';
4
+ export interface ServerTimerUIProps {
5
+ serverNow: string;
6
+ endTime: string;
7
+ size?: TimerSize;
8
+ layout?: TimerLayout;
9
+ theme?: TimerTheme;
10
+ showProgress?: boolean;
11
+ onEnd?: () => void;
12
+ className?: string;
13
+ customColors?: {
14
+ background?: string;
15
+ text?: string;
16
+ unitBackground?: string;
17
+ progress?: string;
18
+ };
19
+ showUnits?: {
20
+ days?: boolean;
21
+ hours?: boolean;
22
+ minutes?: boolean;
23
+ seconds?: boolean;
24
+ };
25
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "server-time-timer-yolabs-ui",
3
+ "version": "1.0.0",
4
+ "description": "FluentUI/SharePoint styled React countdown timer UI for server-time-timer-yoLabs",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "peerDependencies": {
15
+ "react": "^18.0.0",
16
+ "react-dom": "^18.0.0",
17
+ "server-time-timer-yoLabs": "^1.0.0"
18
+ },
19
+ "keywords": [
20
+ "timer",
21
+ "countdown",
22
+ "react",
23
+ "server-time",
24
+ "fluentui",
25
+ "sharepoint",
26
+ "enterprise",
27
+ "ui"
28
+ ],
29
+ "license": "yolabs",
30
+ "author": "Yonas <+251930327375>",
31
+ "dependencies": {
32
+ "server-time-timer-yolabs": "^1.0.2"
33
+ },
34
+ "devDependencies": {
35
+ "@types/react": "^19.2.7",
36
+ "@types/react-dom": "^19.2.3",
37
+ "typescript": "^5.9.3"
38
+ }
39
+ }