Skip to content

Commit 5889ba0

Browse files
committed
[ADD] search in nav
1 parent f88c99f commit 5889ba0

138 files changed

Lines changed: 862 additions & 498 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,7 @@ lazy<T extends ComponentType<unknown>>(load: () => Promise<{ [k:string]: T }>, o
11581158
11591159
### mergeObjects
11601160
1161-
Function that, given two objects version, merges them into a single one. Via an optional parameter _forceUndefinedValue_ you can define how undefined values are treated. [See demo](https://react-tools.ndria.dev/#/utils/mergedObject)
1161+
Function that, given two objects version, merges them into a single one. Via an optional parameter _forceUndefinedValue_ you can define how undefined values are treated. [See demo](https://react-tools.ndria.dev/#/utils/mergeObjects)
11621162
```tsx
11631163
mergeObjects<T extends object>(oldObj: T, newObj: RecursivePartial<T>, forceUndefinedValue?: boolean): T
11641164
```
@@ -1172,7 +1172,7 @@ removePropertiesFromArrayObjects<T, E extends string | number | symbol = keyof T
11721172
11731173
### uniqueElementsArray
11741174
1175-
Function that given one or more array of object, returns a single array with unique elements by a specified property, an array of properties or _none_. [See demo](https://react-tools.ndria.dev/#/utils/removeDuplicatedFromArray)
1175+
Function that given one or more array of object, returns a single array with unique elements by a specified property, an array of properties or _none_. [See demo](https://react-tools.ndria.dev/#/utils/uniqueElementsArray)
11761176
```tsx
11771177
uniqueElementsArray<T extends string | number | boolean | ((...args: unknown[]) => unknown) | bigint | object>(property: keyof T | (keyof T)[] | "none", ...args: (T[])[]): T[]
11781178
```

apps/react-tools-demo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "react-tools-demo",
33
"private": true,
4-
"version": "1.10.2",
4+
"version": "1.10.3",
55
"type": "module",
66
"scripts": {
77
"generator": "node scripts/generateMarkdown.js && node scripts/generateRouter.js && node scripts/generateMainLayout.js",

apps/react-tools-demo/scripts/generateMainLayout.js

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ async function generateImport(router) {
2323
"import { Link, useLocation, useOutlet } from 'react-router-dom';",
2424
"import Logo from '../assets/github.svg';",
2525
"import React from '../assets/react-red.webp';",
26-
"import { useEffect, useCallback, useRef } from 'react';",
26+
"import { useEffect, useCallback, useRef, BaseSyntheticEvent } from 'react';",
2727
"import { CSSTransition, SwitchTransition } from 'react-transition-group'"
2828
]);
2929
}
@@ -46,10 +46,11 @@ function createLinkHooksRoutes(router, stateFiles, lifecycleFiles, performanceFi
4646
stateFiles.forEach(f => {
4747
const [name] = f.split(".");
4848
router.add(' <Link');
49-
router.add(` className={pathname === "/hooks/state/${name}" ? 'active' : ''}`);
5049
router.add(` ref={node => linksRef.current["${name}"] = node}`);
5150
router.add(` to="/hooks/state/${name}"`);
5251
router.add(' onClick={() => {');
52+
router.add(' Object.values(linksRef.current).forEach(l => l?.classList.remove("active"));');
53+
router.add(' linksRef.current["' + name + '"]?.classList.add("active");');
5354
router.add(' containerRef.current?.scrollTo(0, 0);');
5455
router.add(' window.innerWidth < 1190 && closeNav();');
5556
router.add(' }}');
@@ -66,10 +67,11 @@ function createLinkHooksRoutes(router, stateFiles, lifecycleFiles, performanceFi
6667
lifecycleFiles.forEach(f => {
6768
const [name] = f.split(".");
6869
router.add(' <Link');
69-
router.add(` className={pathname === "/hooks/lifecycle/${name}" ? 'active' : ''}`);
7070
router.add(` ref={node => linksRef.current["${name}"] = node}`);
7171
router.add(` to="/hooks/lifecycle/${name}"`);
7272
router.add(' onClick={() => {');
73+
router.add(' Object.values(linksRef.current).forEach(l => l?.classList.remove("active"));');
74+
router.add(' linksRef.current["' + name + '"]?.classList.add("active");');
7375
router.add(' containerRef.current?.scrollTo(0, 0);');
7476
router.add(' window.innerWidth < 1190 && closeNav();');
7577
router.add(' }}');
@@ -86,10 +88,11 @@ function createLinkHooksRoutes(router, stateFiles, lifecycleFiles, performanceFi
8688
performanceFiles.forEach(f => {
8789
const [name] = f.split(".");
8890
router.add(' <Link');
89-
router.add(` className={pathname === "/hooks/performance/${name}" ? 'active' : ''}`);
9091
router.add(` ref={node => linksRef.current["${name}"] = node}`);
9192
router.add(` to="/hooks/performance/${name}"`);
9293
router.add(' onClick={() => {');
94+
router.add(' Object.values(linksRef.current).forEach(l => l?.classList.remove("active"));');
95+
router.add(' linksRef.current["' + name + '"]?.classList.add("active");');
9396
router.add(' containerRef.current?.scrollTo(0, 0);');
9497
router.add(' window.innerWidth < 1190 && closeNav();');
9598
router.add(' }}');
@@ -106,10 +109,11 @@ function createLinkHooksRoutes(router, stateFiles, lifecycleFiles, performanceFi
106109
eventsFiles.forEach(f => {
107110
const [name] = f.split(".");
108111
router.add(' <Link');
109-
router.add(` className={pathname === "/hooks/events/${name}" ? 'active' : ''}`);
110112
router.add(` ref={node => linksRef.current["${name}"] = node}`);
111113
router.add(` to="/hooks/events/${name}"`);
112114
router.add(' onClick={() => {');
115+
router.add(' Object.values(linksRef.current).forEach(l => l?.classList.remove("active"));');
116+
router.add(' linksRef.current["' + name + '"]?.classList.add("active");');
113117
router.add(' containerRef.current?.scrollTo(0, 0);');
114118
router.add(' window.innerWidth < 1190 && closeNav();');
115119
router.add(' }}');
@@ -126,10 +130,11 @@ function createLinkHooksRoutes(router, stateFiles, lifecycleFiles, performanceFi
126130
apiDomFiles.forEach(f => {
127131
const [name] = f.split(".");
128132
router.add(' <Link');
129-
router.add(` className={pathname === "/hooks/api-${name}" ? 'active' : ''}`);
130133
router.add(` ref={node => linksRef.current["${name}"] = node}`);
131134
router.add(` to="/hooks/api-dom/${name}"`);
132135
router.add(' onClick={() => {');
136+
router.add(' Object.values(linksRef.current).forEach(l => l?.classList.remove("active"));');
137+
router.add(' linksRef.current["' + name + '"]?.classList.add("active");');
133138
router.add(' containerRef.current?.scrollTo(0, 0);');
134139
router.add(' window.innerWidth < 1190 && closeNav();');
135140
router.add(' }}');
@@ -156,10 +161,11 @@ function createLinkRoutes(router, componentsFiles, parentRoot) {
156161
componentsFiles.forEach(f => {
157162
const [name] = f.split(".");
158163
router.add(' <Link');
159-
router.add(` className={pathname === "/${parentRoot}/${name}" ? 'active' : ''}`);
160164
router.add(` ref={node => linksRef.current["${name}"] = node}`);
161165
router.add(` to="/${parentRoot}/${name}"`);
162166
router.add(' onClick={() => {');
167+
router.add(' Object.values(linksRef.current).forEach(l => l?.classList.remove("active"));');
168+
router.add(' linksRef.current["' + name + '"]?.classList.add("active");');
163169
router.add(' containerRef.current?.scrollTo(0, 0);');
164170
router.add(' window.innerWidth < 1190 && closeNav();');
165171
router.add(' }}');
@@ -174,9 +180,9 @@ function createLinkRoutes(router, componentsFiles, parentRoot) {
174180

175181
/**
176182
*
177-
* @param {{readonly value: string;add(s: string): this;set(s: string[]): this;}} router
183+
* @returns
178184
*/
179-
async function createLinkRouter(router) {
185+
async function readFiles() {
180186
const libSrcIndexFile = await fs.readFile(path.join(PATH_LIB_SRC, "index.ts"));
181187
const [HOOKS_STATE_FILES, HOOKS_LIFECYCLE_FILES, HOOKS_PERFORMANCE_FILES, HOOKS_EVENTS_FILES, HOOKS_APIDOM_FILES, COMPONENTS_FILES, UTILS_FILES] = await Promise.all([
182188
fs.readFile((path.join(PATH_LIB_SRC, HOOKS_DIR_NAME, HOOKS_TYPE[0], "index.ts")), { encoding: "utf8" }).then(res => res.replaceAll("export { ", "").replaceAll("export ", "").split("\n").map(el => el.substring(0, el.indexOf(" } from") !== -1 ? el.indexOf(" } from") : el.indexOf(" from"))).filter(el => !!el && libSrcIndexFile.includes(el)).sort((a, b) => a.localeCompare(b, 'en'))),
@@ -187,6 +193,40 @@ async function createLinkRouter(router) {
187193
fs.readFile((path.join(PATH_LIB_SRC, COMPONENTS_DIR_NAME, "index.ts")), { encoding: "utf8" }).then(res => res.replaceAll("export { ", "").replaceAll("export ", "").split("\n").map(el => el.substring(0, el.indexOf(" } from") !== -1 ? el.indexOf(" } from") : el.indexOf(" from"))).filter(el => !!el && libSrcIndexFile.includes(el)).sort((a, b) => a.localeCompare(b, 'en'))),
188194
fs.readFile((path.join(PATH_LIB_SRC, UTILS_DIR_NAME, "index.ts")), { encoding: "utf8" }).then(res => res.replaceAll("export { ", "").replaceAll("export ", "").split("\n").map(el => el.substring(0, el.indexOf(" } from") !== -1 ? el.indexOf(" } from") : el.indexOf(" from"))).filter(el => !!el && libSrcIndexFile.includes(el)).sort((a, b) => a.localeCompare(b, 'en')))
189195
]);
196+
197+
return [HOOKS_STATE_FILES, HOOKS_LIFECYCLE_FILES, HOOKS_PERFORMANCE_FILES, HOOKS_EVENTS_FILES, HOOKS_APIDOM_FILES, COMPONENTS_FILES, UTILS_FILES];
198+
}
199+
200+
/**
201+
*
202+
* @param {{readonly value: string;add(s: string): this;set(s: string[]): this;}} router
203+
* @param {*} HOOKS_STATE_FILES
204+
* @param {*} HOOKS_LIFECYCLE_FILES
205+
* @param {*} HOOKS_PERFORMANCE_FILES
206+
* @param {*} HOOKS_EVENTS_FILES
207+
* @param {*} HOOKS_APIDOM_FILES
208+
* @param {*} COMPONENTS_FILES
209+
* @param {*} UTILS_FILES
210+
*/
211+
function addingOptionDataList(router, HOOKS_STATE_FILES, HOOKS_LIFECYCLE_FILES, HOOKS_PERFORMANCE_FILES, HOOKS_EVENTS_FILES, HOOKS_APIDOM_FILES, COMPONENTS_FILES, UTILS_FILES) {
212+
[...HOOKS_STATE_FILES, ...HOOKS_LIFECYCLE_FILES, ...HOOKS_PERFORMANCE_FILES, ...HOOKS_EVENTS_FILES, ...HOOKS_APIDOM_FILES, ...COMPONENTS_FILES, ...UTILS_FILES].forEach(f => {
213+
const [name] = f.split(".");
214+
router.add(` <option value="${name}"></option>`);
215+
})
216+
}
217+
218+
/**
219+
*
220+
* @param {{readonly value: string;add(s: string): this;set(s: string[]): this;}} router
221+
* @param {*} HOOKS_STATE_FILES
222+
* @param {*} HOOKS_LIFECYCLE_FILES
223+
* @param {*} HOOKS_PERFORMANCE_FILES
224+
* @param {*} HOOKS_EVENTS_FILES
225+
* @param {*} HOOKS_APIDOM_FILES
226+
* @param {*} COMPONENTS_FILES
227+
* @param {*} UTILS_FILES
228+
*/
229+
function createLinkRouter(router, HOOKS_STATE_FILES, HOOKS_LIFECYCLE_FILES, HOOKS_PERFORMANCE_FILES, HOOKS_EVENTS_FILES, HOOKS_APIDOM_FILES, COMPONENTS_FILES, UTILS_FILES) {
190230
createLinkHooksRoutes(router, HOOKS_STATE_FILES, HOOKS_LIFECYCLE_FILES, HOOKS_PERFORMANCE_FILES, HOOKS_EVENTS_FILES, HOOKS_APIDOM_FILES);
191231
createLinkRoutes(router, COMPONENTS_FILES, "components")
192232
createLinkRoutes(router, UTILS_FILES, "utils")
@@ -228,6 +268,7 @@ async function generateMainLayout() {
228268
}
229269
}
230270
await generateImport(stringBuffer);
271+
const [HOOKS_STATE_FILES, HOOKS_LIFECYCLE_FILES, HOOKS_PERFORMANCE_FILES, HOOKS_EVENTS_FILES, HOOKS_APIDOM_FILES, COMPONENTS_FILES, UTILS_FILES] = await readFiles();
231272
stringBuffer.set([
232273
"export default function MainLayout() {",
233274
" const { pathname } = useLocation();",
@@ -249,8 +290,10 @@ async function generateMainLayout() {
249290
' }',
250291
' const nodes = Object.values(linksRef.current);',
251292
' for (const node of nodes) {',
252-
' if (node?.getAttribute("href") === window.location.hash && node?.offsetTop > window.innerHeight) {',
253-
' node?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });',
293+
' const hashNode = node?.getAttribute("href") ?? "";',
294+
' if (node && hashNode === window.location.hash) {',
295+
' node?.classList.add("active");',
296+
' node?.offsetTop > window.innerHeight && node?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });',
254297
' break;',
255298
' }',
256299
' }',
@@ -263,17 +306,27 @@ async function generateMainLayout() {
263306
' <button onClick={openNav} className="open-nav">☰</button>',
264307
' <nav ref={navRef} className="nav">',
265308
' <button onClick={closeNav} className="btn-close">X</button>',
266-
' <div className="title-container">',
267-
' <Link to="/" className="title">',
268-
' <img src={React} alt="react" className="img" />',
269-
' <p className="text" translate="no">React Tools</p>',
270-
' </Link>',
271-
' <Link to="https://github.com/nDriaDev/react-tools">',
272-
' <img src={Logo} className="img" alt="github" />',
273-
' </Link>',
274-
' </div>',
309+
' <div className="title-search-container">',
310+
' <div className="title-container">',
311+
' <Link to="/" className="title">',
312+
' <img src={React} alt="react" className="img" />',
313+
' <p className="text" translate="no">React Tools</p>',
314+
' </Link>',
315+
' <Link to="https://github.com/nDriaDev/react-tools">',
316+
' <img src={Logo} className="img" alt="github" />',
317+
' </Link>',
318+
' </div>',
319+
' <div className="search-container">',
320+
' <input list="routes" id="input-routes" name="input-routes" className="search" placeholder="🔎 Search..." onChange={(e: BaseSyntheticEvent) => { linksRef.current[e.target.value]?.click(); linksRef.current[e.target.value]?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }); }} />',
321+
' <datalist id="routes">'
322+
]);
323+
addingOptionDataList(stringBuffer, HOOKS_STATE_FILES, HOOKS_LIFECYCLE_FILES, HOOKS_PERFORMANCE_FILES, HOOKS_EVENTS_FILES, HOOKS_APIDOM_FILES, COMPONENTS_FILES, UTILS_FILES);
324+
stringBuffer.set([
325+
' </datalist>',
326+
' </div>',
327+
' </div>'
275328
]);
276-
await createLinkRouter(stringBuffer);
329+
createLinkRouter(stringBuffer, HOOKS_STATE_FILES, HOOKS_LIFECYCLE_FILES, HOOKS_PERFORMANCE_FILES, HOOKS_EVENTS_FILES, HOOKS_APIDOM_FILES, COMPONENTS_FILES, UTILS_FILES);
277330
stringBuffer.set([
278331
' </nav>',
279332
' </>',

apps/react-tools-demo/src/App.css

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,23 +159,51 @@ code {
159159
align-self: end;
160160
}
161161

162-
.title-container {
163-
background-color: #1a1a1a;
162+
.title-search-container {
164163
position: sticky;
165164
top: 0;
165+
background-color: #1a1a1a;
166166
display: flex;
167-
justify-content: space-between;
168-
align-items: center;
169-
padding: 1em 1em 0em;
167+
flex-direction: column;
168+
169+
.title-container {
170+
display: flex;
171+
justify-content: space-between;
172+
align-items: center;
173+
padding: 1em 1em 0em;
174+
175+
.img {
176+
width: 2em;
177+
height: 1.825em;
178+
vertical-align: text-top;
179+
}
170180

171-
.img {
172-
width: 2em;
173-
height: 1.825em;
174-
vertical-align: text-top;
181+
.img:hover {
182+
filter: drop-shadow(1px 1px 4px #f53340)
183+
}
175184
}
176185

177-
.img:hover {
178-
filter: drop-shadow(1px 1px 4px #f53340)
186+
.search-container {
187+
display: flex;
188+
align-items: center;
189+
padding: 1em 1em 0em;
190+
191+
.search {
192+
display: block;
193+
width: 100%;
194+
padding: .375rem .75rem;
195+
font-size: 1rem;
196+
font-weight: 400;
197+
line-height: 1.5;
198+
color: #92929b;
199+
background-color: #242424;
200+
background-clip: padding-box;
201+
border: 1px solid #242424;
202+
-webkit-appearance: none;
203+
-moz-appearance: none;
204+
appearance: none;
205+
border-radius: .25rem;
206+
}
179207
}
180208
}
181209

@@ -195,6 +223,7 @@ code {
195223
height: 1.825em;
196224
vertical-align: text-top;
197225
}
226+
198227
}
199228

200229
.nav>.type {

0 commit comments

Comments
 (0)