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
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
src/assets/*.json
|
||||
|
||||
123
src/App.jsx
123
src/App.jsx
@@ -1,38 +1,139 @@
|
||||
import { useState } from 'react';
|
||||
import { House } from '@phosphor-icons/react';
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { ArrowRight, House, Trash } from '@phosphor-icons/react';
|
||||
|
||||
import { GREP_A_WORD } from './constants/options'
|
||||
import { OptionsRow } from './components/OptionsRow';
|
||||
|
||||
import wordCountObject from './assets/wordCount.json';
|
||||
|
||||
import styles from './App.module.css'
|
||||
|
||||
import './global.css'
|
||||
|
||||
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() {
|
||||
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 (
|
||||
<div>
|
||||
<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}>
|
||||
<House size={24} />
|
||||
</button>
|
||||
<OptionsRow onSelectOption={selectOption}/>
|
||||
<OptionsRow onSelectOption={selectedOption}/>
|
||||
</header>
|
||||
|
||||
<div className={styles.wrapper}>
|
||||
<h1>Welcome to my diary exposer!</h1>
|
||||
<p>Please select one of the options:</p>
|
||||
<OptionsRow onSelectOption={setSelectOption} />
|
||||
|
||||
{ selectOption &&
|
||||
<p>foo</p>
|
||||
{ !!! selectedOption &&
|
||||
<>
|
||||
<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>
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
margin: 2rem auto;
|
||||
padding: 0 1rem;
|
||||
|
||||
/* display: grid; */
|
||||
/* grid-template-columns: 256px 1fr; */
|
||||
/* gap: 2rem; */
|
||||
/* align-items: flex-start; */
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -47,9 +42,77 @@
|
||||
color: var(--gray-400);
|
||||
cursor: pointer;
|
||||
line-height: 0;
|
||||
border-radius: 2px;
|
||||
border-radius: 8px;
|
||||
transition: color 0.1s;
|
||||
}
|
||||
|
||||
.homeButton:hover {
|
||||
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