Skip to content

Commit f7b15e2

Browse files
committedAug 9, 2024
first commit
0 parents  commit f7b15e2

16 files changed

+2943
-0
lines changed
 

‎.eslintrc.cjs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module.exports = {
2+
root: true,
3+
env: { browser: true, es2020: true },
4+
extends: [
5+
'eslint:recommended',
6+
'plugin:@typescript-eslint/recommended',
7+
'plugin:react-hooks/recommended',
8+
'eslint-config-prettier',
9+
],
10+
ignorePatterns: ['dist', '.eslintrc.cjs'],
11+
parser: '@typescript-eslint/parser',
12+
plugins: ['react-refresh'],
13+
rules: {
14+
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
15+
},
16+
}

‎.gitignore

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

‎.prettierrc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"jsxSingleQuote": true,
3+
"printWidth": 100,
4+
"semi": false,
5+
"singleAttributePerLine": true,
6+
"singleQuote": true,
7+
"tabWidth": 2,
8+
"trailingComma": "es5"
9+
}

‎README.md

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# ranify
2+
3+
**ranify** is a library for creating customizable rain effects for React projects.
4+
5+
## Installation
6+
7+
```bash
8+
pnpm install ranify
9+
# or
10+
npm install ranify
11+
# or
12+
yarn add ranify
13+
```
14+
15+
### Usage
16+
17+
#### React
18+
19+
To use the rain effect in a React project, you can import the component and use it directly in your React components.
20+
21+
Example
22+
23+
1. Import the Components
24+
25+
```tsx
26+
import { Ranify } from 'ranify'
27+
```
28+
29+
2. Use the Component in Your Project
30+
31+
```tsx
32+
import React from 'react'
33+
import { Ranify } from 'ranify'
34+
35+
const App: React.FC = () => {
36+
return (
37+
<div>
38+
<Ranify
39+
intensity={0.5}
40+
speed={3}
41+
direction={{ x: 0, y: 1 }}
42+
color='rgba(255, 255, 255, 0.8)'
43+
thickness={2}
44+
/>
45+
</div>
46+
)
47+
}
48+
49+
export default App
50+
```
51+
52+
### Configuration
53+
54+
#### Component Properties
55+
56+
- **'intensity'** (number): Controls the intensity of the rain. Values between 0 and 1.
57+
- **'speed'** (number): Controls the speed of the rain. Positive values.
58+
- **'direction'** (object): Defines the wind direction with x and y properties.
59+
- **'color'** (string): Defines the color of the raindrops. Example: "rgba(255, 255, 255, 0.8)".
60+
- **'thickness'** (number): Defines the thickness of the raindrops. Positive values.
61+
62+
### Configuration Example
63+
64+
```tsx
65+
<Ranify
66+
intensity={0.7}
67+
speed={5}
68+
direction={{ x: 1, y: 0.5 }}
69+
color='rgba(0, 0, 255, 0.6)'
70+
thickness={3}
71+
/>
72+
```
73+
74+
### Contributing
75+
76+
If you want to contribute to the project, feel free to open issues and pull requests. Please follow the contribution guidelines and maintain code quality.
77+
78+
### License
79+
80+
This project is licensed under the MIT License. See the LICENSE file for more details.
81+
82+
### Contact
83+
84+
If you have any questions or suggestions, please contact us at: thiagotnon@gmail.com.
85+
86+
Thank you for using [ranify](https://github.com/thiagotnon/ranify.git)! We hope you enjoy the rain effect in your projects.
87+
88+
Made with 💜 by [thiagotnon](https://github.com/thiagotnon).

‎package.json

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "rainify",
3+
"private": false,
4+
"version": "0.0.2",
5+
"type": "module",
6+
"files": [
7+
"dist"
8+
],
9+
"module": "./dist/main.js",
10+
"exports": "./dist/main.js",
11+
"types": "./dist/main.d.ts",
12+
"peerDependencies": {
13+
"react": "^18.3.1",
14+
"react-dom": "^18.3.1"
15+
},
16+
"scripts": {
17+
"dev": "vite",
18+
"build": "tsc -b && vite build",
19+
"preview": "vite preview",
20+
"lint": "eslint . --ext ts,tsx",
21+
"lint:fix": "eslint . --ext ts,tsx --fix",
22+
"prepublishOnly": "npm run build",
23+
"publish": "npm publish --access public"
24+
},
25+
"dependencies": {
26+
"react": "^18.3.1",
27+
"react-dom": "^18.3.1"
28+
},
29+
"devDependencies": {
30+
"glob": "^11.0.0",
31+
"@eslint/js": "^9.8.0",
32+
"@types/node": "^22.1.0",
33+
"@types/react": "^18.3.3",
34+
"@types/react-dom": "^18.3.0",
35+
"@vitejs/plugin-react": "^4.3.1",
36+
"eslint": "^9.8.0",
37+
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
38+
"eslint-plugin-react-refresh": "^0.4.9",
39+
"globals": "^15.9.0",
40+
"typescript": "^5.5.3",
41+
"typescript-eslint": "^8.0.0",
42+
"vite": "^5.4.0",
43+
"vite-plugin-dts": "^4.0.1"
44+
}
45+
}

‎pnpm-lock.yaml

+2,534
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎public/vite.svg

+1
Loading

‎src/components/rainify/index.tsx

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { useEffect, useRef } from 'react'
2+
3+
interface RainifyProps {
4+
className?: string
5+
intensity?: number
6+
color?: string
7+
zIndex?: number
8+
speed?: number
9+
wind?: number
10+
thickness?: number
11+
}
12+
13+
interface Raindrop {
14+
x: number
15+
y: number
16+
length: number
17+
velocityY: number
18+
velocityX: number
19+
}
20+
21+
export function Rainify({
22+
className,
23+
intensity = 50,
24+
color = 'rgb(128,128,128, .5)',
25+
zIndex = 0,
26+
speed = 1,
27+
wind = 0,
28+
thickness = 1,
29+
}: RainifyProps) {
30+
const canvasRef = useRef<HTMLCanvasElement>(null)
31+
32+
useEffect(() => {
33+
const canvas = canvasRef.current
34+
if (!canvas) return
35+
36+
const ctx = canvas.getContext('2d')
37+
if (!ctx) return
38+
39+
canvas.width = window.innerWidth
40+
canvas.height = window.innerHeight
41+
42+
const raindrops: Raindrop[] = Array.from({ length: intensity }, () => ({
43+
x: Math.random() * canvas.width,
44+
y: Math.random() * canvas.height,
45+
length: Math.random() * 20 + 10,
46+
velocityY: (Math.random() * 2 + 2) * speed,
47+
velocityX: wind,
48+
}))
49+
50+
const drawRaindrop = (drop: Raindrop) => {
51+
ctx.beginPath()
52+
ctx.moveTo(drop.x, drop.y)
53+
ctx.lineTo(drop.x + drop.velocityX, drop.y + drop.length)
54+
ctx.strokeStyle = color
55+
ctx.lineWidth = thickness
56+
ctx.stroke()
57+
}
58+
59+
const updateRaindrop = (drop: Raindrop) => {
60+
drop.y += drop.velocityY
61+
drop.x += drop.velocityX
62+
63+
if (drop.y > canvas.height) {
64+
drop.y = 0 - drop.length
65+
drop.x = Math.random() * canvas.width
66+
}
67+
68+
if (drop.x > canvas.width) {
69+
drop.x = 0
70+
} else if (drop.x < 0) {
71+
drop.x = canvas.width
72+
}
73+
}
74+
75+
const animate = () => {
76+
ctx.clearRect(0, 0, canvas.width, canvas.height)
77+
raindrops.forEach((drop) => {
78+
drawRaindrop(drop)
79+
updateRaindrop(drop)
80+
})
81+
requestAnimationFrame(animate)
82+
}
83+
84+
animate()
85+
86+
const handleResize = () => {
87+
canvas.width = window.innerWidth
88+
canvas.height = window.innerHeight
89+
}
90+
91+
window.addEventListener('resize', handleResize)
92+
93+
return () => {
94+
window.removeEventListener('resize', handleResize)
95+
}
96+
}, [intensity, color, speed, wind, thickness])
97+
98+
return (
99+
<canvas
100+
className={className}
101+
ref={canvasRef}
102+
style={{ position: 'fixed', top: 0, left: 0, zIndex, pointerEvents: 'none' }}
103+
/>
104+
)
105+
}

‎src/main.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { Rainify } from './components/rainify'

‎src/vite-env.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="vite/client" />

‎tsconfig.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"useDefineForClassFields": true,
5+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
6+
"module": "ESNext",
7+
"skipLibCheck": true,
8+
9+
/* Bundler mode */
10+
"moduleResolution": "bundler",
11+
"allowImportingTsExtensions": true,
12+
"resolveJsonModule": true,
13+
"isolatedModules": true,
14+
"noEmit": true,
15+
"jsx": "react-jsx",
16+
17+
/* Linting */
18+
"strict": true,
19+
"noUnusedLocals": true,
20+
"noUnusedParameters": true,
21+
"noFallthroughCasesInSwitch": true
22+
},
23+
"include": ["src"],
24+
"references": [{ "path": "./tsconfig.node.json" }]
25+
}

‎tsconfig.node.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"composite": true,
4+
"skipLibCheck": true,
5+
"module": "ESNext",
6+
"moduleResolution": "Bundler",
7+
"allowSyntheticDefaultImports": true,
8+
"strict": true
9+
},
10+
"include": ["vite.config.ts"]
11+
}

‎tsconfig.node.tsbuildinfo

+1
Large diffs are not rendered by default.

‎vite.config.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
declare const _default: import("vite").UserConfig;
2+
export default _default;

‎vite.config.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/// <reference types="vite/client"/>
2+
import { defineConfig } from 'vite';
3+
import { fileURLToPath } from 'node:url';
4+
import { globSync } from 'glob';
5+
import react from '@vitejs/plugin-react';
6+
import path, { resolve } from 'node:path';
7+
import dts from 'vite-plugin-dts';
8+
// https://vitejs.dev/config/
9+
export default defineConfig({
10+
plugins: [react(), dts()],
11+
build: {
12+
lib: {
13+
entry: resolve(__dirname, 'src/main.ts'),
14+
formats: ['es'],
15+
},
16+
rollupOptions: {
17+
external: ['react', 'react-dom', 'react/jsx-runtime'],
18+
input: Object.fromEntries(globSync(['src/components/**/index.tsx', 'src/main.ts']).map(function (file) {
19+
// This remove `src/` as well as the file extension from each
20+
// file, so e.g. src/nested/foo.js becomes nested/foo
21+
var entryName = path.relative('src', file.slice(0, file.length - path.extname(file).length));
22+
// This expands the relative paths to absolute paths, so e.g.
23+
// src/nested/foo becomes /project/src/nested/foo.js
24+
var entryUrl = fileURLToPath(new URL(file, import.meta.url));
25+
return [entryName, entryUrl];
26+
})),
27+
output: {
28+
entryFileNames: '[name].js',
29+
globals: {
30+
react: 'React',
31+
'react-dom': 'React-dom',
32+
'react/jsx-runtime': 'react/jsx-runtime',
33+
},
34+
},
35+
},
36+
},
37+
});

‎vite.config.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/// <reference types="vite/client"/>
2+
import { defineConfig } from 'vite'
3+
import { fileURLToPath } from 'node:url'
4+
import { globSync } from 'glob'
5+
import react from '@vitejs/plugin-react'
6+
import path, { resolve } from 'node:path'
7+
import dts from 'vite-plugin-dts'
8+
9+
// https://vitejs.dev/config/
10+
export default defineConfig({
11+
plugins: [react(), dts()],
12+
build: {
13+
lib: {
14+
entry: resolve(__dirname, 'src/main.ts'),
15+
formats: ['es'],
16+
},
17+
rollupOptions: {
18+
external: ['react', 'react-dom', 'react/jsx-runtime'],
19+
input: Object.fromEntries(
20+
globSync(['src/components/**/index.tsx', 'src/main.ts']).map((file) => {
21+
// This remove `src/` as well as the file extension from each
22+
// file, so e.g. src/nested/foo.js becomes nested/foo
23+
const entryName = path.relative(
24+
'src',
25+
file.slice(0, file.length - path.extname(file).length)
26+
)
27+
// This expands the relative paths to absolute paths, so e.g.
28+
// src/nested/foo becomes /project/src/nested/foo.js
29+
const entryUrl = fileURLToPath(new URL(file, import.meta.url))
30+
return [entryName, entryUrl]
31+
})
32+
),
33+
output: {
34+
entryFileNames: '[name].js',
35+
globals: {
36+
react: 'React',
37+
'react-dom': 'React-dom',
38+
'react/jsx-runtime': 'react/jsx-runtime',
39+
},
40+
},
41+
},
42+
},
43+
})

0 commit comments

Comments
 (0)
Please sign in to comment.