omnira-ui 0.1.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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +145 -0
  3. package/cli/omnira-init.mjs +260 -0
  4. package/cli/presets.mjs +386 -0
  5. package/components/ui/AppStoreButton/AppStoreButton.module.css +87 -0
  6. package/components/ui/AppStoreButton/AppStoreButton.tsx +114 -0
  7. package/components/ui/AppStoreButton/index.ts +2 -0
  8. package/components/ui/Avatar/Avatar.module.css +76 -0
  9. package/components/ui/Avatar/Avatar.tsx +102 -0
  10. package/components/ui/Avatar/index.ts +2 -0
  11. package/components/ui/Badge/Badge.module.css +120 -0
  12. package/components/ui/Badge/Badge.tsx +25 -0
  13. package/components/ui/Badge/index.ts +2 -0
  14. package/components/ui/BadgeGroup/BadgeGroup.module.css +214 -0
  15. package/components/ui/BadgeGroup/BadgeGroup.tsx +88 -0
  16. package/components/ui/BadgeGroup/index.ts +2 -0
  17. package/components/ui/Browser/Browser.module.css +105 -0
  18. package/components/ui/Browser/Browser.tsx +54 -0
  19. package/components/ui/Browser/index.ts +2 -0
  20. package/components/ui/Button/Button.module.css +188 -0
  21. package/components/ui/Button/Button.tsx +74 -0
  22. package/components/ui/Button/index.ts +2 -0
  23. package/components/ui/ButtonUtility/ButtonUtility.module.css +154 -0
  24. package/components/ui/ButtonUtility/ButtonUtility.tsx +65 -0
  25. package/components/ui/ButtonUtility/index.ts +2 -0
  26. package/components/ui/Card/Card.module.css +80 -0
  27. package/components/ui/Card/Card.tsx +39 -0
  28. package/components/ui/Card/index.ts +2 -0
  29. package/components/ui/Checkbox/Checkbox.module.css +92 -0
  30. package/components/ui/Checkbox/Checkbox.tsx +95 -0
  31. package/components/ui/Checkbox/index.ts +2 -0
  32. package/components/ui/Collapse/Collapse.module.css +60 -0
  33. package/components/ui/Collapse/Collapse.tsx +100 -0
  34. package/components/ui/Collapse/index.ts +2 -0
  35. package/components/ui/CreditCard/CreditCard.module.css +117 -0
  36. package/components/ui/CreditCard/CreditCard.tsx +86 -0
  37. package/components/ui/CreditCard/index.ts +2 -0
  38. package/components/ui/Dropdown/Dropdown.module.css +269 -0
  39. package/components/ui/Dropdown/Dropdown.tsx +419 -0
  40. package/components/ui/Dropdown/index.ts +31 -0
  41. package/components/ui/GridLines/GridLines.module.css +95 -0
  42. package/components/ui/GridLines/GridLines.tsx +10 -0
  43. package/components/ui/GridLines/index.ts +1 -0
  44. package/components/ui/Illustration/Illustration.module.css +10 -0
  45. package/components/ui/Illustration/Illustration.tsx +96 -0
  46. package/components/ui/Illustration/index.ts +2 -0
  47. package/components/ui/Input/Input.module.css +217 -0
  48. package/components/ui/Input/Input.tsx +93 -0
  49. package/components/ui/Input/index.ts +2 -0
  50. package/components/ui/Phone/Phone.module.css +104 -0
  51. package/components/ui/Phone/Phone.tsx +54 -0
  52. package/components/ui/Phone/index.ts +2 -0
  53. package/components/ui/PinInput/PinInput.module.css +104 -0
  54. package/components/ui/PinInput/PinInput.tsx +210 -0
  55. package/components/ui/PinInput/index.ts +1 -0
  56. package/components/ui/ProgressBar/ProgressBar.module.css +180 -0
  57. package/components/ui/ProgressBar/ProgressBar.tsx +206 -0
  58. package/components/ui/ProgressBar/index.ts +2 -0
  59. package/components/ui/QRCode/QRCode.module.css +13 -0
  60. package/components/ui/QRCode/QRCode.tsx +128 -0
  61. package/components/ui/QRCode/index.ts +2 -0
  62. package/components/ui/RadioButton/RadioButton.module.css +92 -0
  63. package/components/ui/RadioButton/RadioButton.tsx +134 -0
  64. package/components/ui/RadioButton/index.ts +2 -0
  65. package/components/ui/RadioGroup/RadioGroup.module.css +382 -0
  66. package/components/ui/RadioGroup/RadioGroup.tsx +292 -0
  67. package/components/ui/RadioGroup/index.ts +1 -0
  68. package/components/ui/Rating/Rating.module.css +99 -0
  69. package/components/ui/Rating/Rating.tsx +123 -0
  70. package/components/ui/Rating/index.ts +2 -0
  71. package/components/ui/Select/Select.module.css +371 -0
  72. package/components/ui/Select/Select.tsx +507 -0
  73. package/components/ui/Select/index.ts +2 -0
  74. package/components/ui/SidebarNavigation/SidebarDual.tsx +71 -0
  75. package/components/ui/SidebarNavigation/SidebarFeatureCard.module.css +351 -0
  76. package/components/ui/SidebarNavigation/SidebarFeatureCard.tsx +388 -0
  77. package/components/ui/SidebarNavigation/SidebarNavigation.module.css +610 -0
  78. package/components/ui/SidebarNavigation/SidebarParts.tsx +215 -0
  79. package/components/ui/SidebarNavigation/SidebarSectionDividers.tsx +46 -0
  80. package/components/ui/SidebarNavigation/SidebarSectionHeadings.tsx +52 -0
  81. package/components/ui/SidebarNavigation/SidebarSimple.tsx +46 -0
  82. package/components/ui/SidebarNavigation/SidebarSlim.tsx +48 -0
  83. package/components/ui/SidebarNavigation/index.ts +29 -0
  84. package/components/ui/SidebarNavigation/types.ts +27 -0
  85. package/components/ui/Slider/Slider.module.css +93 -0
  86. package/components/ui/Slider/Slider.tsx +118 -0
  87. package/components/ui/Slider/index.ts +2 -0
  88. package/components/ui/SocialButton/SocialButton.module.css +223 -0
  89. package/components/ui/SocialButton/SocialButton.tsx +185 -0
  90. package/components/ui/SocialButton/index.ts +2 -0
  91. package/components/ui/Tag/Tag.module.css +203 -0
  92. package/components/ui/Tag/Tag.tsx +161 -0
  93. package/components/ui/Tag/index.ts +2 -0
  94. package/components/ui/TextEditor/TextEditor.module.css +182 -0
  95. package/components/ui/TextEditor/TextEditor.tsx +323 -0
  96. package/components/ui/TextEditor/index.ts +1 -0
  97. package/components/ui/Textarea/Textarea.module.css +75 -0
  98. package/components/ui/Textarea/Textarea.tsx +59 -0
  99. package/components/ui/Textarea/index.ts +2 -0
  100. package/components/ui/Toggle/Toggle.module.css +118 -0
  101. package/components/ui/Toggle/Toggle.tsx +77 -0
  102. package/components/ui/Toggle/index.ts +2 -0
  103. package/components/ui/Tooltip/Tooltip.module.css +95 -0
  104. package/components/ui/Tooltip/Tooltip.tsx +55 -0
  105. package/components/ui/Tooltip/index.ts +2 -0
  106. package/components/ui/VideoPlayer/VideoPlayer.module.css +120 -0
  107. package/components/ui/VideoPlayer/VideoPlayer.tsx +229 -0
  108. package/components/ui/VideoPlayer/index.ts +2 -0
  109. package/lib/cn.ts +3 -0
  110. package/lib/copy-to-clipboard.ts +21 -0
  111. package/package.json +61 -0
@@ -0,0 +1,229 @@
1
+ "use client";
2
+
3
+ import { useState, useRef, useCallback, useEffect, forwardRef } from "react";
4
+ import { cn } from "@/lib/cn";
5
+ import styles from "./VideoPlayer.module.css";
6
+
7
+ export interface VideoPlayerProps {
8
+ src: string;
9
+ thumbnailUrl?: string;
10
+ size?: "sm" | "md" | "lg";
11
+ autoPlay?: boolean;
12
+ muted?: boolean;
13
+ loop?: boolean;
14
+ className?: string;
15
+ }
16
+
17
+ export const VideoPlayer = forwardRef<HTMLDivElement, VideoPlayerProps>(
18
+ (
19
+ {
20
+ src,
21
+ thumbnailUrl,
22
+ size = "md",
23
+ autoPlay = false,
24
+ muted = false,
25
+ loop = false,
26
+ className,
27
+ },
28
+ ref,
29
+ ) => {
30
+ const videoRef = useRef<HTMLVideoElement>(null);
31
+ const [playing, setPlaying] = useState(autoPlay);
32
+ const [progress, setProgress] = useState(0);
33
+ const [duration, setDuration] = useState(0);
34
+ const [currentTime, setCurrentTime] = useState(0);
35
+ const [showControls, setShowControls] = useState(true);
36
+ const [started, setStarted] = useState(autoPlay);
37
+ const [volume, setVolume] = useState(muted ? 0 : 1);
38
+ const [isFullscreen, setIsFullscreen] = useState(false);
39
+ const hideTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
40
+
41
+ const togglePlay = useCallback(() => {
42
+ const v = videoRef.current;
43
+ if (!v) return;
44
+ if (!started) setStarted(true);
45
+ if (v.paused) {
46
+ v.play();
47
+ setPlaying(true);
48
+ } else {
49
+ v.pause();
50
+ setPlaying(false);
51
+ }
52
+ }, [started]);
53
+
54
+ const handleTimeUpdate = useCallback(() => {
55
+ const v = videoRef.current;
56
+ if (!v || !v.duration) return;
57
+ setCurrentTime(v.currentTime);
58
+ setProgress((v.currentTime / v.duration) * 100);
59
+ }, []);
60
+
61
+ const handleLoadedMetadata = useCallback(() => {
62
+ const v = videoRef.current;
63
+ if (v) setDuration(v.duration);
64
+ }, []);
65
+
66
+ const handleSeek = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
67
+ const v = videoRef.current;
68
+ if (!v) return;
69
+ const rect = e.currentTarget.getBoundingClientRect();
70
+ const ratio = (e.clientX - rect.left) / rect.width;
71
+ v.currentTime = ratio * v.duration;
72
+ }, []);
73
+
74
+ const toggleMute = useCallback(() => {
75
+ const v = videoRef.current;
76
+ if (!v) return;
77
+ if (v.volume > 0) {
78
+ v.volume = 0;
79
+ setVolume(0);
80
+ } else {
81
+ v.volume = 1;
82
+ setVolume(1);
83
+ }
84
+ }, []);
85
+
86
+ const toggleFullscreen = useCallback(() => {
87
+ const el = videoRef.current?.parentElement;
88
+ if (!el) return;
89
+ if (!document.fullscreenElement) {
90
+ el.requestFullscreen?.();
91
+ setIsFullscreen(true);
92
+ } else {
93
+ document.exitFullscreen?.();
94
+ setIsFullscreen(false);
95
+ }
96
+ }, []);
97
+
98
+ const handleMouseMove = useCallback(() => {
99
+ setShowControls(true);
100
+ clearTimeout(hideTimer.current);
101
+ if (playing) {
102
+ hideTimer.current = setTimeout(() => setShowControls(false), 2500);
103
+ }
104
+ }, [playing]);
105
+
106
+ useEffect(() => {
107
+ return () => clearTimeout(hideTimer.current);
108
+ }, []);
109
+
110
+ const fmt = (s: number) => {
111
+ const m = Math.floor(s / 60);
112
+ const sec = Math.floor(s % 60);
113
+ return `${m}:${sec.toString().padStart(2, "0")}`;
114
+ };
115
+
116
+ return (
117
+ <div
118
+ ref={ref}
119
+ className={cn(styles.player, styles[`player_${size}`], className)}
120
+ onMouseMove={handleMouseMove}
121
+ onMouseLeave={() => playing && setShowControls(false)}
122
+ >
123
+ {/* Thumbnail overlay */}
124
+ {!started && thumbnailUrl && (
125
+ <div className={styles.thumbnail} onClick={togglePlay}>
126
+ <img src={thumbnailUrl} alt="Video thumbnail" className={styles.thumbnailImg} />
127
+ <button className={styles.playBtnLarge} aria-label="Play video">
128
+ <PlayIcon />
129
+ </button>
130
+ </div>
131
+ )}
132
+
133
+ <video
134
+ ref={videoRef}
135
+ src={src}
136
+ className={styles.video}
137
+ onTimeUpdate={handleTimeUpdate}
138
+ onLoadedMetadata={handleLoadedMetadata}
139
+ onEnded={() => setPlaying(false)}
140
+ autoPlay={autoPlay}
141
+ muted={muted}
142
+ loop={loop}
143
+ playsInline
144
+ onClick={togglePlay}
145
+ />
146
+
147
+ {/* Controls bar */}
148
+ {started && (
149
+ <div className={cn(styles.controls, showControls && styles.controlsVisible)}>
150
+ <button className={styles.controlBtn} onClick={togglePlay} aria-label={playing ? "Pause" : "Play"}>
151
+ {playing ? <PauseIcon /> : <PlaySmallIcon />}
152
+ </button>
153
+
154
+ <span className={styles.time}>{fmt(currentTime)}</span>
155
+
156
+ <div className={styles.progressTrack} onClick={handleSeek}>
157
+ <div className={styles.progressFill} style={{ width: `${progress}%` }} />
158
+ </div>
159
+
160
+ <span className={styles.time}>{fmt(duration)}</span>
161
+
162
+ <button className={styles.controlBtn} onClick={toggleMute} aria-label={volume === 0 ? "Unmute" : "Mute"}>
163
+ {volume === 0 ? <MuteIcon /> : <VolumeIcon />}
164
+ </button>
165
+
166
+ <button className={styles.controlBtn} onClick={toggleFullscreen} aria-label="Fullscreen">
167
+ <FullscreenIcon />
168
+ </button>
169
+ </div>
170
+ )}
171
+ </div>
172
+ );
173
+ },
174
+ );
175
+
176
+ VideoPlayer.displayName = "VideoPlayer";
177
+
178
+ /* ── Inline SVG Icons ── */
179
+ function PlayIcon() {
180
+ return (
181
+ <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
182
+ <circle cx="24" cy="24" r="24" fill="rgba(0,0,0,0.5)" />
183
+ <path d="M19 15L33 24L19 33V15Z" fill="white" />
184
+ </svg>
185
+ );
186
+ }
187
+
188
+ function PlaySmallIcon() {
189
+ return (
190
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
191
+ <path d="M4 2L14 8L4 14V2Z" fill="currentColor" />
192
+ </svg>
193
+ );
194
+ }
195
+
196
+ function PauseIcon() {
197
+ return (
198
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
199
+ <rect x="3" y="2" width="4" height="12" rx="1" fill="currentColor" />
200
+ <rect x="9" y="2" width="4" height="12" rx="1" fill="currentColor" />
201
+ </svg>
202
+ );
203
+ }
204
+
205
+ function VolumeIcon() {
206
+ return (
207
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
208
+ <path d="M2 6H5L9 2V14L5 10H2V6Z" fill="currentColor" />
209
+ <path d="M11 5.5C11.8 6.3 12.3 7.5 12.3 8S11.8 9.7 11 10.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
210
+ </svg>
211
+ );
212
+ }
213
+
214
+ function MuteIcon() {
215
+ return (
216
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
217
+ <path d="M2 6H5L9 2V14L5 10H2V6Z" fill="currentColor" />
218
+ <path d="M12 6L14 8M14 6L12 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
219
+ </svg>
220
+ );
221
+ }
222
+
223
+ function FullscreenIcon() {
224
+ return (
225
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
226
+ <path d="M2 6V3C2 2.4 2.4 2 3 2H6M10 2H13C13.6 2 14 2.4 14 3V6M14 10V13C14 13.6 13.6 14 13 14H10M6 14H3C2.4 14 2 13.6 2 13V10" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
227
+ </svg>
228
+ );
229
+ }
@@ -0,0 +1,2 @@
1
+ export { VideoPlayer } from "./VideoPlayer";
2
+ export type { VideoPlayerProps } from "./VideoPlayer";
package/lib/cn.ts ADDED
@@ -0,0 +1,3 @@
1
+ export function cn(...classes: (string | undefined | null | false)[]): string {
2
+ return classes.filter(Boolean).join(" ");
3
+ }
@@ -0,0 +1,21 @@
1
+ export async function copyToClipboard(text: string): Promise<boolean> {
2
+ try {
3
+ await navigator.clipboard.writeText(text);
4
+ return true;
5
+ } catch {
6
+ const textarea = document.createElement("textarea");
7
+ textarea.value = text;
8
+ textarea.style.position = "fixed";
9
+ textarea.style.opacity = "0";
10
+ document.body.appendChild(textarea);
11
+ textarea.select();
12
+ try {
13
+ document.execCommand("copy");
14
+ return true;
15
+ } catch {
16
+ return false;
17
+ } finally {
18
+ document.body.removeChild(textarea);
19
+ }
20
+ }
21
+ }
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "omnira-ui",
3
+ "version": "0.1.0",
4
+ "description": "A premium glassmorphism design system — dark-first, glass-forward. 30+ base components, sidebar navigation, feature cards, and a CLI to scaffold your project.",
5
+ "keywords": [
6
+ "design-system",
7
+ "glassmorphism",
8
+ "dark-mode",
9
+ "ui-components",
10
+ "react",
11
+ "nextjs",
12
+ "css-modules",
13
+ "component-library",
14
+ "accessibility",
15
+ "typescript"
16
+ ],
17
+ "author": "Siri <siri@intraopic.com>",
18
+ "license": "MIT",
19
+ "homepage": "https://ui.omnira.space",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/nidrosoft/omniraui.git"
23
+ },
24
+ "bin": {
25
+ "omnira-ui": "./cli/omnira-init.mjs"
26
+ },
27
+ "files": [
28
+ "cli/",
29
+ "components/ui/",
30
+ "lib/cn.ts",
31
+ "lib/copy-to-clipboard.ts",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "scripts": {
39
+ "dev": "next dev",
40
+ "build": "next build",
41
+ "start": "next start",
42
+ "init": "node cli/omnira-init.mjs"
43
+ },
44
+ "dependencies": {
45
+ "@icons-pack/react-simple-icons": "^13.11.2",
46
+ "@types/react-syntax-highlighter": "^15.5.13",
47
+ "framer-motion": "^12.34.0",
48
+ "iconsax-react": "^0.0.8",
49
+ "next": "16.1.6",
50
+ "react": "19.2.3",
51
+ "react-dom": "19.2.3",
52
+ "react-syntax-highlighter": "^16.1.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^20",
56
+ "@types/react": "^19",
57
+ "@types/react-dom": "^19",
58
+ "babel-plugin-react-compiler": "1.0.0",
59
+ "typescript": "^5"
60
+ }
61
+ }