Skip to content

Commit 8b30403

Browse files
committed
feat: integrate Tailwind CSS and Framer Motion for enhanced UI
- Added Tailwind CSS and PostCSS configuration for styling. - Introduced Framer Motion for animations throughout the application. - Refactored App component to utilize new UI components: Header, TitleSection, FeatureIcons, FingerprintPanel, GenerateButton, and Instructions. - Created reusable UI components (Button, Badge, Card) with class variance authority for styling. - Implemented a responsive design with Tailwind CSS utility classes. - Added new dependencies: class-variance-authority, clsx, framer-motion, lucide-react, tailwind-merge, and tailwindcss. - Updated TypeScript configuration for module path aliases.
1 parent cf44bed commit 8b30403

18 files changed

+1860
-498
lines changed

example/package-lock.json

Lines changed: 1374 additions & 394 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/package.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,23 @@
1111
"@types/node": "^16.11.27",
1212
"@types/react": "^18.0.5",
1313
"@types/react-dom": "^18.0.1",
14+
"class-variance-authority": "^0.7.1",
15+
"clsx": "^2.1.1",
16+
"framer-motion": "^11.18.2",
17+
"lucide-react": "^0.441.0",
1418
"react": "^18.0.0",
1519
"react-dom": "^18.0.0",
1620
"react-scripts": "5.0.1",
21+
"tailwind-merge": "^2.6.0",
22+
"tw-animate-css": "^1.3.6",
1723
"typescript": "^4.6.3",
1824
"web-vitals": "^2.1.4"
1925
},
26+
"devDependencies": {
27+
"autoprefixer": "^10.4.20",
28+
"postcss": "^8.4.41",
29+
"tailwindcss": "^3.4.10"
30+
},
2031
"scripts": {
2132
"start": "react-scripts start",
2233
"build": "react-scripts build",
@@ -41,4 +52,4 @@
4152
"last 1 safari version"
4253
]
4354
}
44-
}
55+
}

example/postcss.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}

example/src/App.css

Lines changed: 95 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,101 @@
1-
body, html{
2-
padding: 0px;
3-
margin: 0px;
4-
overflow-x: hidden;
5-
width: 100%;
6-
height: 100%;
7-
}
8-
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
94

10-
.App {
11-
display: flex;
12-
flex-direction: column;
13-
align-items: center;
14-
justify-content: center;
15-
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
16-
background-color: #282c34;
17-
min-height: 100vh;
18-
width: 100%;
19-
font-size: calc(60px + 2vmin);
20-
color: white;
21-
/* padding: 10px; */
22-
}
23-
.App .header{
24-
display: flex;
25-
flex-direction: column;
26-
align-items: center;
27-
justify-content: center;
28-
text-align: center;
29-
}
30-
.App p{
31-
font-size: 14px;
32-
max-width: 800px;
33-
margin: auto;
34-
text-align: center;
35-
}
36-
.App p b{
37-
color: #f71137;
38-
font-size: 16px;
5+
:root {
6+
--background: 223.8136 -172.5242% 100.0000%;
7+
--foreground: 223.8136 0.0000% 3.9388%;
8+
--card: 223.8136 -172.5242% 100.0000%;
9+
--card-foreground: 223.8136 0.0000% 3.9388%;
10+
--popover: 223.8136 -172.5242% 100.0000%;
11+
--popover-foreground: 223.8136 0.0000% 3.9388%;
12+
--primary: 223.8136 0.0000% 9.0527%;
13+
--primary-foreground: 223.8136 0.0004% 98.0256%;
14+
--secondary: 223.8136 0.0002% 96.0587%;
15+
--secondary-foreground: 223.8136 0.0000% 9.0527%;
16+
--muted: 223.8136 0.0002% 96.0587%;
17+
--muted-foreground: 223.8136 0.0000% 45.1519%;
18+
--accent: 223.8136 0.0002% 96.0587%;
19+
--accent-foreground: 223.8136 0.0000% 9.0527%;
20+
--destructive: 351.7303 123.6748% 40.5257%;
21+
--destructive-foreground: 223.8136 -172.5242% 100.0000%;
22+
--border: 223.8136 0.0001% 89.8161%;
23+
--input: 223.8136 0.0001% 89.8161%;
24+
--ring: 223.8136 0.0000% 63.0163%;
25+
--chart-1: 211.7880 101.9718% 78.6759%;
26+
--chart-2: 217.4076 91.3672% 59.5787%;
27+
--chart-3: 221.4336 86.3731% 54.0624%;
28+
--chart-4: 223.6587 78.7180% 47.8635%;
29+
--chart-5: 226.5426 70.0108% 39.9224%;
30+
--sidebar: 223.8136 0.0004% 98.0256%;
31+
--sidebar-foreground: 223.8136 0.0000% 3.9388%;
32+
--sidebar-primary: 223.8136 0.0000% 9.0527%;
33+
--sidebar-primary-foreground: 223.8136 0.0004% 98.0256%;
34+
--sidebar-accent: 223.8136 0.0002% 96.0587%;
35+
--sidebar-accent-foreground: 223.8136 0.0000% 9.0527%;
36+
--sidebar-border: 223.8136 0.0001% 89.8161%;
37+
--sidebar-ring: 223.8136 0.0000% 63.0163%;
38+
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
39+
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
40+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
41+
--radius: 0.625rem;
42+
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
43+
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
44+
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
45+
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
46+
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10);
47+
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10);
48+
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10);
49+
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
50+
--tracking-normal: 0em;
51+
--spacing: 0.25rem;
3952
}
4053

41-
.App .id-container{
42-
margin-top: 20px;
43-
}
44-
.App .id-container textarea{
45-
font-size: 30px;
46-
max-width: 900px;
47-
width: 100%;
48-
padding: 20px;
49-
}
50-
.App .id-container button{
51-
padding: 10px 25px;
52-
color: white;
53-
background: #f71137;
54-
border: 1px solid #f71137;
55-
border-radius: 5px;
56-
cursor: pointer;
57-
}
58-
.App .id-container button:hover {
59-
background: #f8072f;
60-
}
61-
62-
footer{
63-
margin-top: 80px;
64-
font-size: 24px;
65-
display: flex;
66-
justify-content: center;
67-
align-items: center;
68-
flex-wrap: wrap;
69-
70-
}
71-
footer a{
72-
color: #f71137 !important;
73-
}
74-
footer div{
75-
margin: 10px;
54+
.dark {
55+
--background: 223.8136 0.0000% 3.9388%;
56+
--foreground: 223.8136 0.0004% 98.0256%;
57+
--card: 223.8136 0.0000% 9.0527%;
58+
--card-foreground: 223.8136 0.0004% 98.0256%;
59+
--popover: 223.8136 0.0000% 14.9382%;
60+
--popover-foreground: 223.8136 0.0004% 98.0256%;
61+
--primary: 223.8136 0.0001% 89.8161%;
62+
--primary-foreground: 223.8136 0.0000% 9.0527%;
63+
--secondary: 223.8136 0.0000% 14.9382%;
64+
--secondary-foreground: 223.8136 0.0004% 98.0256%;
65+
--muted: 223.8136 0.0000% 14.9382%;
66+
--muted-foreground: 223.8136 0.0000% 63.0163%;
67+
--accent: 223.8136 0.0000% 25.0471%;
68+
--accent-foreground: 223.8136 0.0004% 98.0256%;
69+
--destructive: 358.7594 101.8439% 69.8357%;
70+
--destructive-foreground: 223.8136 0.0004% 98.0256%;
71+
--border: 223.8136 0.0000% 15.5096%;
72+
--input: 223.8136 0.0000% 20.3885%;
73+
--ring: 223.8136 0.0000% 45.1519%;
74+
--chart-1: 211.7880 101.9718% 78.6759%;
75+
--chart-2: 217.4076 91.3672% 59.5787%;
76+
--chart-3: 221.4336 86.3731% 54.0624%;
77+
--chart-4: 223.6587 78.7180% 47.8635%;
78+
--chart-5: 226.5426 70.0108% 39.9224%;
79+
--sidebar: 223.8136 0.0000% 9.0527%;
80+
--sidebar-foreground: 223.8136 0.0004% 98.0256%;
81+
--sidebar-primary: 225.3451 84.0953% 48.9841%;
82+
--sidebar-primary-foreground: 223.8136 0.0004% 98.0256%;
83+
--sidebar-accent: 223.8136 0.0000% 14.9382%;
84+
--sidebar-accent-foreground: 223.8136 0.0004% 98.0256%;
85+
--sidebar-border: 223.8136 0.0000% 15.5096%;
86+
--sidebar-ring: 223.8136 0.0000% 32.1993%;
87+
--font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
88+
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
89+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
90+
--radius: 0.625rem;
91+
--shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
92+
--shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05);
93+
--shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
94+
--shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10);
95+
--shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10);
96+
--shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10);
97+
--shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10);
98+
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
7699
}
77100

78101

example/src/App.tsx

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,83 @@
1-
import { getCurrentBrowserFingerPrint } from '@rajesh896/broprint.js';
2-
import { useState } from 'react';
3-
import './App.css';
4-
1+
import { useState } from 'react'
2+
import { motion } from 'framer-motion'
3+
import { getCurrentBrowserFingerPrint } from '@rajesh896/broprint.js'
4+
import { Header } from './components/Header'
5+
import { TitleSection } from './components/TitleSection'
6+
import { FeatureIcons } from './components/FeatureIcons'
7+
import { FingerprintPanel } from './components/FingerprintPanel'
8+
import { GenerateButton } from './components/GenerateButton'
9+
import { Instructions } from './components/Instructions'
10+
import './App.css'
511

612
function App() {
7-
const [browserFingerprint, setBrowserFingerPrint] = useState("");
8-
const getBrowserFingerPrint = () => {
9-
getCurrentBrowserFingerPrint().then((res) => {
10-
setBrowserFingerPrint(res)
11-
}).catch((err) => {
12-
setBrowserFingerPrint(JSON.stringify(err))
13-
})
14-
}
15-
13+
const [fingerprint, setFingerprint] = useState<string | undefined>('')
14+
const [isGenerating, setIsGenerating] = useState(false)
15+
const [copied, setCopied] = useState(false)
16+
17+
18+
const generateFingerprint = async () => {
19+
setIsGenerating(true)
20+
try {
21+
const fp = await getCurrentBrowserFingerPrint()
22+
// simulate delay
23+
await new Promise((resolve) => {
24+
setTimeout(() => {
25+
setFingerprint(String(fp));
26+
resolve(fp);
27+
}, 1500);
28+
})
29+
} catch (e: any) {
30+
setFingerprint('ERROR:' + (e?.message || 'failed'))
31+
} finally {
32+
setIsGenerating(false)
33+
}
34+
}
35+
36+
const copyToClipboard = async () => {
37+
if (!fingerprint) return
38+
try {
39+
await navigator.clipboard.writeText(fingerprint)
40+
setCopied(true)
41+
setTimeout(() => setCopied(false), 2000)
42+
} catch (_) { /* noop */ }
43+
}
44+
1645
return (
17-
<div className="App">
18-
<div className='header'>
19-
<header >
20-
Browser FingerPrint
21-
</header>
22-
<p>This package generates a unique ID/String for different browsers. Like chrome, firefox and any other browser which supports <b>canvas fingerPrinting</b> and <b>audio FingerPrinting</b>.</p>
46+
<div className="min-h-screen bg-black relative overflow-hidden App">
47+
{/* Animated Background Grid */}
48+
<div className="absolute inset-0 opacity-20">
49+
<div className="absolute inset-0 bg-gradient-to-br from-cyan-500/10 via-blue-500/10 to-emerald-500/10" />
50+
<motion.div
51+
className="absolute inset-0"
52+
style={{
53+
backgroundImage: `linear-gradient(rgba(0,255,255,0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(0,255,255,0.1) 1px, transparent 1px)`,
54+
backgroundSize: '50px 50px'
55+
}}
56+
animate={{ backgroundPosition: ['0px 0px', '50px 50px'] }}
57+
transition={{ duration: 20, repeat: Infinity, ease: 'linear' }}
58+
/>
59+
</div>
60+
{/* Floating Particles */}
61+
{[...Array(12)].map((_, i) => (
62+
<motion.div
63+
key={i}
64+
className="absolute rounded-full"
65+
style={{ width: 4, height: 4, background: '#22d3ee' }}
66+
initial={{ x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight }}
67+
animate={{ x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight }}
68+
transition={{ duration: Math.random() * 10 + 10, repeat: Infinity, repeatType: 'reverse' }}
69+
/>
70+
))}
71+
<div className="relative z-10 container mx-auto px-4 py-8" style={{ maxWidth: 1400 }}>
72+
<Header />
73+
<TitleSection />
74+
<FeatureIcons />
75+
<FingerprintPanel fingerprint={fingerprint} isGenerating={isGenerating} copied={copied} onCopy={copyToClipboard} />
76+
<GenerateButton isGenerating={isGenerating} onClick={generateFingerprint} />
77+
<Instructions />
2378
</div>
24-
<section className="id-container">
25-
<textarea rows={3} cols={100} placeholder="This browser's fingerprint" value={browserFingerprint} onChange={() => {}}></textarea>
26-
<p><button onClick={() => {getBrowserFingerPrint()}}>Generate FingerPrint</button></p>
27-
<p style={{marginTop: 20}}>You must try this window in incognito, with vpn and check if Id remains same. It will never change. <sub>[no brave support]</sub></p>
28-
</section>
29-
<footer>
30-
<div><a href='https://x.com/Raj_896' title='developer/author twitter or X account'>@Raj_896</a></div>
31-
<div><a title='go to github link of this repo' href='https://github.com/Rajesh-Royal/Broprint.js'>GitHub</a></div>
32-
</footer>
3379
</div>
34-
);
80+
)
3581
}
3682

37-
export default App;
83+
export default App

example/src/components.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": false,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "",
8+
"css": "src/styles/globals.css",
9+
"baseColor": "neutral",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "@/components",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib",
18+
"hooks": "@/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { motion } from 'framer-motion'
2+
import { Shield, Cpu, Globe, Lock } from 'lucide-react'
3+
import React from 'react'
4+
5+
const features = [
6+
{ icon: Shield, label: 'Secure', color: '#4ade80' },
7+
{ icon: Cpu, label: 'Fast', color: '#60a5fa' },
8+
{ icon: Globe, label: 'Universal', color: '#34d399' },
9+
{ icon: Lock, label: 'Private', color: '#ec4899' }
10+
]
11+
12+
export const FeatureIcons: React.FC = () => (
13+
<motion.div className="flex justify-center flex-wrap gap-8 mb-12" initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.8, delay: 0.6 }}>
14+
{features.map((f, i) => (
15+
<motion.div key={f.label} className="flex flex-col items-center gap-2" whileHover={{ scale: 1.1 }} initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, delay: 0.8 + i * 0.1 }}>
16+
<motion.div style={{ padding: 12, borderRadius: '9999px', border: `1px solid ${f.color}`, background: f.color + '20' }} animate={{ boxShadow: ['0 0 20px ' + f.color + '40', '0 0 30px ' + f.color + '60', '0 0 20px ' + f.color + '40'] }} transition={{ duration: 2, repeat: Infinity }}>
17+
<f.icon className="w-6 h-6" color={f.color} />
18+
</motion.div>
19+
<span style={{ fontSize: 12, color: f.color, fontWeight: 600 }}>{f.label}</span>
20+
</motion.div>
21+
))}
22+
</motion.div>
23+
)

0 commit comments

Comments
 (0)