nnews-react 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/LICENSE +21 -0
- package/README.md +575 -0
- package/dist/index.cjs +57 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +534 -0
- package/dist/index.js +29836 -0
- package/dist/index.js.map +1 -0
- package/dist/style.css +10 -0
- package/package.json +129 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 NAuth Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
# nnews-react
|
|
2
|
+
|
|
3
|
+
Complete React component library for NAuth authentication and NNews content management system. Built with TypeScript, Tailwind CSS, and designed as a distributable NPM package.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/nnews-react)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
### Authentication (NAuth)
|
|
11
|
+
✨ **Complete Auth Suite** - Login, Register, Password Recovery, Change Password
|
|
12
|
+
👤 **User Management** - Full CRUD with profile editing
|
|
13
|
+
🎭 **Role Management** - Role-based access control
|
|
14
|
+
🎯 **Security** - Device fingerprinting with FingerprintJS
|
|
15
|
+
🔒 **Type-Safe** - Full TypeScript support
|
|
16
|
+
|
|
17
|
+
### Content Management (NNews)
|
|
18
|
+
📝 **Article Management** - Full CRUD with Markdown editor
|
|
19
|
+
📂 **Category System** - Hierarchical categories with parent-child relationships
|
|
20
|
+
🏷️ **Tag Management** - Flexible tagging with merge functionality
|
|
21
|
+
✍️ **Markdown Editor** - Live preview with syntax highlighting
|
|
22
|
+
👁️ **Article Viewer** - Beautiful article display with GitHub-flavored Markdown
|
|
23
|
+
🔐 **Access Control** - Role-based content visibility
|
|
24
|
+
|
|
25
|
+
### General
|
|
26
|
+
🎨 **Theme Support** - Light/Dark mode with system detection
|
|
27
|
+
📦 **Tree-shakeable** - Import only what you need
|
|
28
|
+
♿ **Accessible** - WCAG compliant
|
|
29
|
+
📱 **Responsive** - Mobile-first design
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install nnews-react react react-dom react-router-dom
|
|
35
|
+
|
|
36
|
+
# If you don't have Tailwind CSS
|
|
37
|
+
npm install -D tailwindcss postcss autoprefixer tailwindcss-animate
|
|
38
|
+
npx tailwindcss init -p
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Configure Tailwind
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// tailwind.config.js
|
|
45
|
+
export default {
|
|
46
|
+
darkMode: ['class'],
|
|
47
|
+
content: [
|
|
48
|
+
'./src/**/*.{js,ts,jsx,tsx}',
|
|
49
|
+
'./node_modules/nnews-react/dist/**/*.{js,ts,jsx,tsx}',
|
|
50
|
+
],
|
|
51
|
+
theme: {
|
|
52
|
+
extend: {
|
|
53
|
+
typography: {
|
|
54
|
+
DEFAULT: {
|
|
55
|
+
css: {
|
|
56
|
+
maxWidth: 'none',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
plugins: [
|
|
63
|
+
require('tailwindcss-animate'),
|
|
64
|
+
require('@tailwindcss/typography'), // For Markdown rendering
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```css
|
|
70
|
+
/* src/index.css */
|
|
71
|
+
@tailwind base;
|
|
72
|
+
@tailwind components;
|
|
73
|
+
@tailwind utilities;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Quick Start
|
|
77
|
+
|
|
78
|
+
### 1. Setup Providers
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
82
|
+
import { NAuthProvider, NNewsProvider, ThemeProvider } from 'nnews-react';
|
|
83
|
+
import 'nnews-react/styles';
|
|
84
|
+
import './index.css';
|
|
85
|
+
|
|
86
|
+
function App() {
|
|
87
|
+
return (
|
|
88
|
+
<BrowserRouter>
|
|
89
|
+
<ThemeProvider defaultTheme="system">
|
|
90
|
+
<NAuthProvider
|
|
91
|
+
config={{
|
|
92
|
+
apiUrl: import.meta.env.VITE_API_URL,
|
|
93
|
+
enableFingerprinting: true,
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
96
|
+
<NNewsProvider
|
|
97
|
+
config={{
|
|
98
|
+
apiUrl: import.meta.env.VITE_API_URL,
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
<YourApp />
|
|
102
|
+
</NNewsProvider>
|
|
103
|
+
</NAuthProvider>
|
|
104
|
+
</ThemeProvider>
|
|
105
|
+
</BrowserRouter>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```env
|
|
111
|
+
# .env
|
|
112
|
+
VITE_API_URL=https://your-nauth-api.com
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 2. Use Authentication Components
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import {
|
|
119
|
+
LoginForm,
|
|
120
|
+
RegisterForm,
|
|
121
|
+
UserEditForm,
|
|
122
|
+
RoleList,
|
|
123
|
+
SearchForm,
|
|
124
|
+
useAuth,
|
|
125
|
+
useProtectedRoute,
|
|
126
|
+
} from 'nnews-react';
|
|
127
|
+
import { useNavigate } from 'react-router-dom';
|
|
128
|
+
|
|
129
|
+
// Login Page
|
|
130
|
+
function LoginPage() {
|
|
131
|
+
const navigate = useNavigate();
|
|
132
|
+
return (
|
|
133
|
+
<div className="min-h-screen flex items-center justify-center">
|
|
134
|
+
<LoginForm
|
|
135
|
+
onSuccess={() => navigate('/dashboard')}
|
|
136
|
+
showRememberMe
|
|
137
|
+
showForgotPassword
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Protected Dashboard
|
|
144
|
+
function Dashboard() {
|
|
145
|
+
const { user, logout } = useAuth();
|
|
146
|
+
useProtectedRoute({ redirectTo: '/login' });
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<div>
|
|
150
|
+
<h1>Welcome, {user?.name}</h1>
|
|
151
|
+
<button onClick={logout}>Logout</button>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// User Management
|
|
157
|
+
function CreateUserPage() {
|
|
158
|
+
const navigate = useNavigate();
|
|
159
|
+
return (
|
|
160
|
+
<UserEditForm
|
|
161
|
+
onSuccess={(user) => {
|
|
162
|
+
console.log('User created:', user);
|
|
163
|
+
navigate('/users');
|
|
164
|
+
}}
|
|
165
|
+
onCancel={() => navigate('/users')}
|
|
166
|
+
/>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 3. Use Content Management Components
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import {
|
|
175
|
+
ArticleList,
|
|
176
|
+
ArticleViewer,
|
|
177
|
+
ArticleEditor,
|
|
178
|
+
CategoryList,
|
|
179
|
+
CategoryModal,
|
|
180
|
+
TagList,
|
|
181
|
+
TagModal,
|
|
182
|
+
useArticles,
|
|
183
|
+
useCategories,
|
|
184
|
+
useTags,
|
|
185
|
+
} from 'nnews-react';
|
|
186
|
+
|
|
187
|
+
// Articles List Page
|
|
188
|
+
function ArticlesPage() {
|
|
189
|
+
const { articles, loading, fetchArticles, deleteArticle } = useArticles();
|
|
190
|
+
|
|
191
|
+
useEffect(() => {
|
|
192
|
+
fetchArticles({ page: 1, pageSize: 20 });
|
|
193
|
+
}, []);
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div className="container mx-auto p-6">
|
|
197
|
+
<h1 className="text-3xl font-bold mb-6">Articles</h1>
|
|
198
|
+
<ArticleList
|
|
199
|
+
articles={articles}
|
|
200
|
+
loading={loading}
|
|
201
|
+
onArticleClick={(article) => navigate(`/articles/${article.id}`)}
|
|
202
|
+
onEditClick={(article) => navigate(`/articles/${article.id}/edit`)}
|
|
203
|
+
onDeleteClick={deleteArticle}
|
|
204
|
+
showActions
|
|
205
|
+
/>
|
|
206
|
+
</div>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Article Viewer Page
|
|
211
|
+
function ArticleViewPage({ articleId }: { articleId: number }) {
|
|
212
|
+
const { getArticleById } = useArticles();
|
|
213
|
+
const [article, setArticle] = useState(null);
|
|
214
|
+
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
getArticleById(articleId).then(setArticle);
|
|
217
|
+
}, [articleId]);
|
|
218
|
+
|
|
219
|
+
if (!article) return <div>Loading...</div>;
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<ArticleViewer
|
|
223
|
+
article={article}
|
|
224
|
+
onBack={() => navigate('/articles')}
|
|
225
|
+
onEdit={(article) => navigate(`/articles/${article.id}/edit`)}
|
|
226
|
+
showActions
|
|
227
|
+
/>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Article Editor Page
|
|
232
|
+
function ArticleEditorPage({ articleId }: { articleId?: number }) {
|
|
233
|
+
const { createArticle, updateArticle, getArticleById } = useArticles();
|
|
234
|
+
const { categories } = useCategories();
|
|
235
|
+
const { tags } = useTags();
|
|
236
|
+
const [article, setArticle] = useState(null);
|
|
237
|
+
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
if (articleId) {
|
|
240
|
+
getArticleById(articleId).then(setArticle);
|
|
241
|
+
}
|
|
242
|
+
fetchCategories();
|
|
243
|
+
fetchTags();
|
|
244
|
+
}, [articleId]);
|
|
245
|
+
|
|
246
|
+
const handleSave = async (data) => {
|
|
247
|
+
if (article) {
|
|
248
|
+
await updateArticle({ ...data, id: article.id });
|
|
249
|
+
} else {
|
|
250
|
+
await createArticle(data);
|
|
251
|
+
}
|
|
252
|
+
navigate('/articles');
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<ArticleEditor
|
|
257
|
+
article={article}
|
|
258
|
+
categories={categories}
|
|
259
|
+
tags={tags}
|
|
260
|
+
onSave={handleSave}
|
|
261
|
+
onCancel={() => navigate('/articles')}
|
|
262
|
+
/>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Category Management
|
|
267
|
+
function CategoriesPage() {
|
|
268
|
+
const { categories, createCategory, updateCategory, deleteCategory } = useCategories();
|
|
269
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
270
|
+
const [selectedCategory, setSelectedCategory] = useState(null);
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<div className="container mx-auto p-6">
|
|
274
|
+
<div className="flex justify-between mb-6">
|
|
275
|
+
<h1 className="text-3xl font-bold">Categories</h1>
|
|
276
|
+
<button onClick={() => setModalOpen(true)}>New Category</button>
|
|
277
|
+
</div>
|
|
278
|
+
<CategoryList
|
|
279
|
+
categories={categories}
|
|
280
|
+
onEditClick={(cat) => {
|
|
281
|
+
setSelectedCategory(cat);
|
|
282
|
+
setModalOpen(true);
|
|
283
|
+
}}
|
|
284
|
+
onDeleteClick={deleteCategory}
|
|
285
|
+
showActions
|
|
286
|
+
/>
|
|
287
|
+
<CategoryModal
|
|
288
|
+
isOpen={modalOpen}
|
|
289
|
+
onClose={() => {
|
|
290
|
+
setModalOpen(false);
|
|
291
|
+
setSelectedCategory(null);
|
|
292
|
+
}}
|
|
293
|
+
category={selectedCategory}
|
|
294
|
+
categories={categories}
|
|
295
|
+
onSave={selectedCategory ? updateCategory : createCategory}
|
|
296
|
+
/>
|
|
297
|
+
</div>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Components
|
|
303
|
+
|
|
304
|
+
### Authentication Components
|
|
305
|
+
- `LoginForm` - Email/password login with validation
|
|
306
|
+
- `RegisterForm` - Multi-step registration with password strength
|
|
307
|
+
- `ForgotPasswordForm` - Password recovery request
|
|
308
|
+
- `ResetPasswordForm` - Password reset with token
|
|
309
|
+
- `ChangePasswordForm` - Change password for authenticated users
|
|
310
|
+
|
|
311
|
+
### User Management
|
|
312
|
+
- `UserEditForm` - Create and edit users with full profile management (dual mode)
|
|
313
|
+
- `SearchForm` - Search and browse users with pagination
|
|
314
|
+
|
|
315
|
+
### Role Management
|
|
316
|
+
- `RoleList` - List and manage roles with CRUD operations
|
|
317
|
+
- `RoleForm` - Create and edit roles
|
|
318
|
+
|
|
319
|
+
### Content Management (News)
|
|
320
|
+
- `ArticleList` - Display paginated list of articles with actions
|
|
321
|
+
- `ArticleViewer` - Beautiful article display with Markdown rendering
|
|
322
|
+
- `ArticleEditor` - Full-featured article editor with Markdown support
|
|
323
|
+
- `MarkdownEditor` - Standalone Markdown editor with live preview
|
|
324
|
+
- `CategoryList` - Display and manage categories
|
|
325
|
+
- `CategoryModal` - Modal for creating/editing categories
|
|
326
|
+
- `TagList` - Display and manage tags
|
|
327
|
+
- `TagModal` - Modal for creating/editing tags
|
|
328
|
+
|
|
329
|
+
### UI Components
|
|
330
|
+
`Button`, `Input`, `Label`, `Card`, `Avatar`, `DropdownMenu`, `Toaster`
|
|
331
|
+
|
|
332
|
+
## Hooks
|
|
333
|
+
|
|
334
|
+
### Authentication Hooks
|
|
335
|
+
```tsx
|
|
336
|
+
// Authentication state
|
|
337
|
+
const { user, isAuthenticated, login, logout, isLoading } = useAuth();
|
|
338
|
+
|
|
339
|
+
// User management
|
|
340
|
+
const {
|
|
341
|
+
user,
|
|
342
|
+
updateUser,
|
|
343
|
+
createUser,
|
|
344
|
+
getUserById,
|
|
345
|
+
changePassword,
|
|
346
|
+
uploadImage,
|
|
347
|
+
searchUsers,
|
|
348
|
+
} = useUser();
|
|
349
|
+
|
|
350
|
+
// Role management
|
|
351
|
+
const { fetchRoles, getRoleById, createRole, updateRole, deleteRole } = useNAuth();
|
|
352
|
+
|
|
353
|
+
// Route protection
|
|
354
|
+
useProtectedRoute({ redirectTo: '/login', requireAdmin: false });
|
|
355
|
+
|
|
356
|
+
// Theme management
|
|
357
|
+
const { theme, setTheme } = useTheme();
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Content Management Hooks
|
|
361
|
+
```tsx
|
|
362
|
+
// Article management
|
|
363
|
+
const {
|
|
364
|
+
articles,
|
|
365
|
+
loading,
|
|
366
|
+
error,
|
|
367
|
+
fetchArticles,
|
|
368
|
+
getArticleById,
|
|
369
|
+
createArticle,
|
|
370
|
+
updateArticle,
|
|
371
|
+
deleteArticle,
|
|
372
|
+
refresh,
|
|
373
|
+
} = useArticles();
|
|
374
|
+
|
|
375
|
+
// Category management
|
|
376
|
+
const {
|
|
377
|
+
categories,
|
|
378
|
+
loading,
|
|
379
|
+
error,
|
|
380
|
+
fetchCategories,
|
|
381
|
+
getCategoryById,
|
|
382
|
+
createCategory,
|
|
383
|
+
updateCategory,
|
|
384
|
+
deleteCategory,
|
|
385
|
+
refresh,
|
|
386
|
+
} = useCategories();
|
|
387
|
+
|
|
388
|
+
// Tag management
|
|
389
|
+
const {
|
|
390
|
+
tags,
|
|
391
|
+
loading,
|
|
392
|
+
error,
|
|
393
|
+
fetchTags,
|
|
394
|
+
getTagById,
|
|
395
|
+
createTag,
|
|
396
|
+
updateTag,
|
|
397
|
+
deleteTag,
|
|
398
|
+
mergeTags,
|
|
399
|
+
refresh,
|
|
400
|
+
} = useTags();
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Configuration
|
|
404
|
+
|
|
405
|
+
### NAuth Configuration
|
|
406
|
+
```tsx
|
|
407
|
+
<NAuthProvider
|
|
408
|
+
config={{
|
|
409
|
+
apiUrl: 'https://your-api.com', // Required
|
|
410
|
+
timeout: 30000, // Optional
|
|
411
|
+
enableFingerprinting: true, // Optional
|
|
412
|
+
storageType: 'localStorage', // Optional
|
|
413
|
+
redirectOnUnauthorized: '/login', // Optional
|
|
414
|
+
onAuthChange: (user) => {}, // Optional
|
|
415
|
+
onLogin: (user) => {}, // Optional
|
|
416
|
+
onLogout: () => {}, // Optional
|
|
417
|
+
}}
|
|
418
|
+
>
|
|
419
|
+
<App />
|
|
420
|
+
</NAuthProvider>
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### NNews Configuration
|
|
424
|
+
```tsx
|
|
425
|
+
<NNewsProvider
|
|
426
|
+
config={{
|
|
427
|
+
apiUrl: 'https://your-api.com', // Required
|
|
428
|
+
timeout: 30000, // Optional
|
|
429
|
+
}}
|
|
430
|
+
>
|
|
431
|
+
<App />
|
|
432
|
+
</NNewsProvider>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## API Clients
|
|
436
|
+
|
|
437
|
+
### NAuth API Client
|
|
438
|
+
```tsx
|
|
439
|
+
import { createNAuthClient } from 'nnews-react';
|
|
440
|
+
|
|
441
|
+
const authApi = createNAuthClient({ apiUrl: 'https://your-api.com' });
|
|
442
|
+
|
|
443
|
+
await authApi.login({ email, password });
|
|
444
|
+
await authApi.getMe();
|
|
445
|
+
await authApi.updateUser({ name: 'New Name' });
|
|
446
|
+
await authApi.uploadImage(file);
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### NNews API Services
|
|
450
|
+
```tsx
|
|
451
|
+
import { ArticleAPI, CategoryAPI, TagAPI } from 'nnews-react';
|
|
452
|
+
import axios from 'axios';
|
|
453
|
+
|
|
454
|
+
const apiClient = axios.create({ baseURL: 'https://your-api.com' });
|
|
455
|
+
|
|
456
|
+
// Article API
|
|
457
|
+
const articleApi = new ArticleAPI(apiClient);
|
|
458
|
+
await articleApi.listArticles();
|
|
459
|
+
await articleApi.getArticleById(id);
|
|
460
|
+
await articleApi.createArticle(data);
|
|
461
|
+
await articleApi.updateArticle(data);
|
|
462
|
+
await articleApi.deleteArticle(id);
|
|
463
|
+
|
|
464
|
+
// Category API
|
|
465
|
+
const categoryApi = new CategoryAPI(apiClient);
|
|
466
|
+
await categoryApi.listCategories();
|
|
467
|
+
await categoryApi.createCategory(data);
|
|
468
|
+
|
|
469
|
+
// Tag API
|
|
470
|
+
const tagApi = new TagAPI(apiClient);
|
|
471
|
+
await tagApi.listTags();
|
|
472
|
+
await tagApi.mergeTags(sourceId, targetId);
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## Customization
|
|
476
|
+
|
|
477
|
+
```tsx
|
|
478
|
+
<LoginForm
|
|
479
|
+
className="shadow-2xl"
|
|
480
|
+
styles={{
|
|
481
|
+
container: 'bg-white',
|
|
482
|
+
button: 'bg-purple-600',
|
|
483
|
+
}}
|
|
484
|
+
/>
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
## Utilities
|
|
488
|
+
|
|
489
|
+
```tsx
|
|
490
|
+
import {
|
|
491
|
+
validateCPF,
|
|
492
|
+
validateCNPJ,
|
|
493
|
+
validateEmail,
|
|
494
|
+
formatPhone,
|
|
495
|
+
validatePasswordStrength,
|
|
496
|
+
cn, // Utility for merging Tailwind classes
|
|
497
|
+
} from 'nnews-react';
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
## Markdown Support
|
|
501
|
+
|
|
502
|
+
The Markdown editor supports:
|
|
503
|
+
|
|
504
|
+
- **Basic Formatting**: Bold, italic, strikethrough
|
|
505
|
+
- **Headers**: H1-H6
|
|
506
|
+
- **Lists**: Ordered and unordered
|
|
507
|
+
- **Links**: Inline and reference-style
|
|
508
|
+
- **Images**: Inline images
|
|
509
|
+
- **Code**: Inline code and fenced code blocks with syntax highlighting
|
|
510
|
+
- **Tables**: GitHub-flavored tables
|
|
511
|
+
- **Task Lists**: GitHub-style checkboxes
|
|
512
|
+
- **Blockquotes**: Quote blocks
|
|
513
|
+
|
|
514
|
+
## TypeScript
|
|
515
|
+
|
|
516
|
+
```tsx
|
|
517
|
+
import type {
|
|
518
|
+
// Auth types
|
|
519
|
+
UserInfo,
|
|
520
|
+
LoginCredentials,
|
|
521
|
+
NAuthConfig,
|
|
522
|
+
Theme,
|
|
523
|
+
// News types
|
|
524
|
+
Article,
|
|
525
|
+
Category,
|
|
526
|
+
Tag,
|
|
527
|
+
ArticleStatus,
|
|
528
|
+
ArticleInput,
|
|
529
|
+
ArticleUpdate,
|
|
530
|
+
CategoryInput,
|
|
531
|
+
CategoryUpdate,
|
|
532
|
+
TagInput,
|
|
533
|
+
TagUpdate,
|
|
534
|
+
} from 'nnews-react';
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## Project Structure
|
|
538
|
+
|
|
539
|
+
```
|
|
540
|
+
src/
|
|
541
|
+
├── components/ # Auth forms + News components + UI components
|
|
542
|
+
├── contexts/ # NAuthContext, NNewsContext, ThemeContext
|
|
543
|
+
├── hooks/ # useAuth, useUser, useArticles, useCategories, useTags, etc.
|
|
544
|
+
├── services/ # NAuth API client + News API services
|
|
545
|
+
├── types/ # TypeScript definitions (auth + news)
|
|
546
|
+
├── utils/ # Validators, formatters, utilities
|
|
547
|
+
└── styles/ # Tailwind CSS
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
## Development
|
|
551
|
+
|
|
552
|
+
```bash
|
|
553
|
+
npm install # Install dependencies
|
|
554
|
+
npm run dev # Development mode
|
|
555
|
+
npm run build # Build library
|
|
556
|
+
npm test # Run tests
|
|
557
|
+
npm run lint # Run ESLint
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
## Publishing
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
npm run build
|
|
564
|
+
npm publish --access public
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
## License
|
|
568
|
+
|
|
569
|
+
MIT © [Rodrigo Landim](https://github.com/landim32)
|
|
570
|
+
|
|
571
|
+
## Links
|
|
572
|
+
|
|
573
|
+
- [GitHub](https://github.com/landim32/NNews/tree/main/nnews-react)
|
|
574
|
+
- [NPM](https://www.npmjs.com/package/nnews-react)
|
|
575
|
+
- [Documentation](https://github.com/landim32/NNews/tree/main/nnews-react#readme)
|