New features and get-diary-word-count-script
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -22,3 +22,5 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
src/assets/*.json
|
||||||
|
|||||||
123
src/App.jsx
123
src/App.jsx
@@ -1,38 +1,139 @@
|
|||||||
import { useState } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { House } from '@phosphor-icons/react';
|
import { ArrowRight, House, Trash } from '@phosphor-icons/react';
|
||||||
|
|
||||||
import { GREP_A_WORD } from './constants/options'
|
import { GREP_A_WORD } from './constants/options'
|
||||||
import { OptionsRow } from './components/OptionsRow';
|
import { OptionsRow } from './components/OptionsRow';
|
||||||
|
|
||||||
|
import wordCountObject from './assets/wordCount.json';
|
||||||
|
|
||||||
import styles from './App.module.css'
|
import styles from './App.module.css'
|
||||||
|
|
||||||
import './global.css'
|
import './global.css'
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
const [selectOption, setSelectOption] = useState('');
|
const [selectedOption, setSelectedOption] = useState(GREP_A_WORD);
|
||||||
|
const [inputValue, setInputValue] = useState('');
|
||||||
|
const [wordCount, setWordCount] = useState('');
|
||||||
|
const [isCleanFormButtonDisabled, setIsCleanFormButtonDisabled] = useState(true);
|
||||||
|
const [isSubmitButtonDisabled, setIsSubmitButtonDisabled] = useState(true);
|
||||||
|
|
||||||
|
const inputRef = useRef(null);
|
||||||
|
|
||||||
function handleHomeButtonClick() {
|
function handleHomeButtonClick() {
|
||||||
setSelectOption('');
|
setSelectedOption('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleInputValueChange() {
|
||||||
|
const inputStr = event.target.value;
|
||||||
|
|
||||||
|
if(!event.target.value) {
|
||||||
|
setInputValue('');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inputStr.match(/^[a-zA-Z0-9À-ú]+$/)) return;
|
||||||
|
|
||||||
|
setInputValue(inputStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmitForm() {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const inputValueStr = inputValue.toLowerCase();
|
||||||
|
|
||||||
|
if (!wordCountObject.hasOwnProperty(inputValueStr)) {
|
||||||
|
setWordCount('no');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWordCount(wordCountObject[inputValueStr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCleanForm() {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
setInputValue('');
|
||||||
|
setWordCount('');
|
||||||
|
inputRef.current.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyUpInput() {
|
||||||
|
const enterKeyCharCode = 13;
|
||||||
|
if (event.keyCode !== enterKeyCharCode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputValue === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmitForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputValue === '') {
|
||||||
|
setIsSubmitButtonDisabled(true);
|
||||||
|
} else {
|
||||||
|
setIsSubmitButtonDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [inputValue])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if ([inputValue, wordCount].every((varStr) => varStr === '')) {
|
||||||
|
setIsCleanFormButtonDisabled(true);
|
||||||
|
} else {
|
||||||
|
setIsCleanFormButtonDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [inputValue, wordCount])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<img src={'https://static-00.iconduck.com/assets.00/sushi-emoji-2048x2048-5itsruw8.png'} />
|
|
||||||
<p>My diary exposer</p>
|
|
||||||
<button className={styles.homeButton} onClick={handleHomeButtonClick}>
|
<button className={styles.homeButton} onClick={handleHomeButtonClick}>
|
||||||
<House size={24} />
|
<House size={24} />
|
||||||
</button>
|
</button>
|
||||||
<OptionsRow onSelectOption={selectOption}/>
|
<OptionsRow onSelectOption={selectedOption}/>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<h1>Welcome to my diary exposer!</h1>
|
<h1>Welcome to my diary exposer!</h1>
|
||||||
<p>Please select one of the options:</p>
|
|
||||||
<OptionsRow onSelectOption={setSelectOption} />
|
|
||||||
|
|
||||||
{ selectOption &&
|
{ !!! selectedOption &&
|
||||||
<p>foo</p>
|
<>
|
||||||
|
<p>Please select one of the options:</p>
|
||||||
|
<OptionsRow onSelectOption={setSelectedOption} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
{ selectedOption &&
|
||||||
|
<>
|
||||||
|
<div className={styles.optionInfo}>
|
||||||
|
<h2>Mode: Grep a word</h2>
|
||||||
|
<h3>Please input a word to see how many times it's mentioned in my diary:</h3>
|
||||||
|
<p>(it's case insensitive)</p>
|
||||||
|
</div>
|
||||||
|
<div className={styles.form}>
|
||||||
|
<input type='text' ref={inputRef} value={inputValue} onChange={handleInputValueChange} maxLength={16} onKeyUp={onKeyUpInput} />
|
||||||
|
<button onClick={handleSubmitForm} disabled={isSubmitButtonDisabled} >
|
||||||
|
<ArrowRight size={24} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button className={styles.cleanFormButton} onClick={handleCleanForm} disabled={isCleanFormButtonDisabled}>
|
||||||
|
<Trash size={24} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
{ wordCount &&
|
||||||
|
<>
|
||||||
|
<div className={styles.result}>
|
||||||
|
<p>There are</p>
|
||||||
|
<p className={styles.wordCount}> {wordCount} </p>
|
||||||
|
<p>occurrences of this word in my diary!</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,11 +3,6 @@
|
|||||||
margin: 2rem auto;
|
margin: 2rem auto;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
|
|
||||||
/* display: grid; */
|
|
||||||
/* grid-template-columns: 256px 1fr; */
|
|
||||||
/* gap: 2rem; */
|
|
||||||
/* align-items: flex-start; */
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -47,9 +42,77 @@
|
|||||||
color: var(--gray-400);
|
color: var(--gray-400);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
border-radius: 2px;
|
border-radius: 8px;
|
||||||
|
transition: color 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.homeButton:hover {
|
.homeButton:hover {
|
||||||
color: var(--ice-cold);
|
color: var(--ice-cold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.optionInfo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form button + button {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form button {
|
||||||
|
padding: 0.65rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
border: solid 1px;
|
||||||
|
background-color: var(--gray-600);
|
||||||
|
color: var(--white);
|
||||||
|
margin-left: 1rem;
|
||||||
|
|
||||||
|
transition: color 0.1s;
|
||||||
|
transition: background-color 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form button:disabled {
|
||||||
|
background-color: var(--gray-400);
|
||||||
|
color: var(--black);
|
||||||
|
border: none;
|
||||||
|
border-color: --var(--gray-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form button:enabled:hover {
|
||||||
|
background: var(--green-300);
|
||||||
|
color: var(--white);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form input {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
width: 24vw;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result p {
|
||||||
|
display: inline;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .wordCount {
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
18
src/assets/get-diary-word-count.sh
Executable file
18
src/assets/get-diary-word-count.sh
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
notes_path=$1
|
||||||
|
|
||||||
|
if [ -z "$notes_path" ]; then
|
||||||
|
echo "Usage: `basename @0` [notes-path]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
find "$notes_path" \
|
||||||
|
-type f -name '*.md' -exec cat {} + | \
|
||||||
|
sed 's/[^[:alnum:][:space:]]//g' | \
|
||||||
|
tr '[:upper:]' '[:lower:]' | \
|
||||||
|
tr '[:space:]' '[\n*]' | \
|
||||||
|
sort | \
|
||||||
|
uniq -c | \
|
||||||
|
awk '{print "{\"" $2 "\": " $1 "}"}' | \
|
||||||
|
jq -s 'add' > wordCount.json
|
||||||
Reference in New Issue
Block a user