Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kyoya0819 committed Aug 27, 2024
1 parent 442261e commit d756ffc
Show file tree
Hide file tree
Showing 16 changed files with 968 additions and 381 deletions.
6 changes: 6 additions & 0 deletions .idea/jsLinters/eslint.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 23 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,34 @@
"stylelint:fix": "stylelint \"**/*.{css,scss,sass}\" --fix"
},
"dependencies": {
"@ky-y./ui": "^1.0.68",
"next": "^14.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^5.0.1",
"@ky-y./ui": "^1.0.145",
"next": "^14.2.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.2.1",
"react-textarea-autosize": "^8.5.3",
"sass": "^1.70.0",
"uuid": "^9.0.1"
"sass": "^1.77.8",
"sonner": "^1.5.0",
"use-interval": "^1.4.0",
"uuid": "^10.0.0"
},
"devDependencies": {
"@types/node": "^20.11.15",
"@types/react": "^18.2.51",
"@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^6.19.1",
"@typescript-eslint/parser": "^6.19.1",
"eslint": "^8.56.0",
"eslint-config-next": "^14.1.0",
"@types/node": "^20.14.11",
"@types/react": "^18.3.3",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^7.16.1",
"@typescript-eslint/parser": "^7.16.1",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.5",
"eslint-plugin-import": "^2.29.1",
"postcss-scss": "^4.0.9",
"prettier": "^3.2.4",
"stylelint": "^16.2.1",
"stylelint-config-recess-order": "^4.4.0",
"stylelint-config-standard": "^36.0.0",
"stylelint-prettier": "^5.0.0",
"stylelint-scss": "^6.1.0",
"typescript": "^5.3.3"
"prettier": "^3.3.3",
"stylelint": "^16.7.0",
"stylelint-config-recess-order": "^5.0.1",
"stylelint-config-standard": "^36.0.1",
"stylelint-prettier": "^5.0.2",
"stylelint-scss": "^6.4.1",
"typescript": "^5.5.3"
},
"packageManager": "[email protected]"
}
6 changes: 6 additions & 0 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ export const Header = () => {
<Link href="/password">
Password Maker
</Link>
<Link href="/character-counter">
Character Counter
</Link>
<Link href="/hex-mixer">
Hex Mixer
</Link>
</HeaderC>
);
};
25 changes: 25 additions & 0 deletions src/pages/character-counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Footer, Main } from "@ky-y./ui";
import type { NextPage } from "next";
import Head from "next/head";

import { Header } from "components/Header/Header";

import { Counter } from "sections/character-counter";

const Password: NextPage = () => {

return (
<>
<Head>
<title>Character Counter | kyTools</title>
</Head>
<Header />
<Main>
<Counter />
</Main>
<Footer/>
</>
);
};

export default Password;
25 changes: 25 additions & 0 deletions src/pages/hex-mixer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Footer, Main } from "@ky-y./ui";
import type { NextPage } from "next";
import Head from "next/head";

import { Header } from "components/Header/Header";

import { Mixer } from "sections/hex-mixer";

const Password: NextPage = () => {

return (
<>
<Head>
<title>Hex Mixer | kyTools</title>
</Head>
<Header />
<Main>
<Mixer />
</Main>
<Footer/>
</>
);
};

export default Password;
64 changes: 64 additions & 0 deletions src/sections/character-counter/Counter/Counter.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.textarea {
width: 100%;
}

.data {
margin-top: 2rem;

.default {
text-align: center;

.title {
font-size: 1rem;
}

.count {
font-size: 2.5rem;
line-height: 1.25;
}
}

.others {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-top: 2rem;
text-align: center;

li {
flex: 1;

@media screen and (max-width: 600px) {
min-width: 50%;

&:nth-of-type(n+3) {
margin-top: 1rem;
}
}

.title {
font-size: .75rem;
}

.count {
font-size: 1.5rem;
line-height: 1.25;
}
}
}

@media screen and (min-width: 1000px) {
display: flex;
align-items: center;

.default {
flex-shrink: 0;
width: 35%;
}

.others {
width: 65%;
margin-top: 0;
}
}
}
153 changes: 153 additions & 0 deletions src/sections/character-counter/Counter/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import {Card, Section, Textarea} from "@ky-y./ui";
import { FC, useEffect, useState } from "react";
import useInterval from "use-interval";

import removeReturn from "./scripts/removeReturn";

import scss from "./Counter.module.scss";

export const Counter: FC = () => {
// Intl.Segmenter
const [segmenter, setSegmenter] = useState<Intl.Segmenter | undefined>(undefined);

// 入力値
const [text, setText] = useState<string>("");

// 改行削除済み入力値
const [textDelReturn, setTextDelReturn] = useState<string>("");

// 文字数(軽量版)
const [textCount, setTextCount] = useState<number>(0);

// 文字数(Intl.Segmenter版)
const [segmentCount, setSegmentCount] = useState<number>(0);

// 読み上げ目安秒数
const [second, setSecond] = useState<number>(0);

// 軽量化スクリプト
const [interval, setInterval] = useState<number | null>(null);

useInterval(() => {

if (segmenter)
setSegmentCount([...segmenter.segment(textDelReturn)].length);

setTextCount([...textDelReturn].length);
}, interval);

useEffect(() => {

setText(window.localStorage.getItem("text") ?? "");

if (Intl.Segmenter)
setSegmenter(new Intl.Segmenter("ja", { granularity: "grapheme" }));
}, []);

useEffect(() => {

const textDelReturn = removeReturn(text);
setTextDelReturn(textDelReturn);

const lightCount = [...textDelReturn].length;

setTextCount(lightCount);

if (10000 < lightCount)
setInterval(null);

else if (2000 < lightCount)
setInterval(1000);

else {
setInterval(null);

if (segmenter)
setSegmentCount([...segmenter.segment(textDelReturn)].length);
}

// 1分間に300文字がプレゼンにいいらしい。
setSecond(Math.ceil(lightCount / 300 * 60));

}, [segmenter, text]);

return (
<Section inner>
<Card>
<Textarea
className={scss.textarea}
minRows={3} maxRows={20}
placeholder="文字数をカウントしたい文章を入力してください。"
onChange={e => {
setText(e.target.value);
window.localStorage.setItem("text", e.target.value);
}}
value={text}
/>

<div className={scss.data}>

<div className={scss.default}>
<div className={scss.title}>文字数</div>
<div className={scss.count}>{[...textDelReturn].length}</div>
</div>

<ul className={scss.others}>
<li>
<div className={scss.title}>Intl.Segmenter</div>
<div className={scss.count}>{
10000 < textCount
? "Not Support"
: segmenter
? segmentCount
: "Not Support"
}</div>
</li>
<li>
<div className={scss.title}>文字数(空白なし)</div>
<div className={scss.count}>{
[
...textDelReturn
.replace(/\s/g, "")
].length
}</div>
</li>
<li>
<div className={scss.title}>バイト数(UTF-8)</div>
<div className={scss.count}>{
encodeURI(textDelReturn).replace(/%../g, "*").length
}</div>
</li>
<li>
<div className={scss.title}>行数</div>
<div className={scss.count}>{
[...text].length
- [...removeReturn(text)].length
- (text.match(/\r\n/g) || []).length
+ (text === "" ? 0 : 1)
}</div>
</li>
<li>
<div className={scss.title}>読む目安</div>
<div className={scss.count}>
{
3600 > second
? ""
: Math.floor(second / 3600) + "h "
}
{
60 > second
? ""
: Math.floor(second % 3600 / 60) + "m "
}
{
second % 60 + "s"
}
</div>
</li>
</ul>
</div>
</Card>
</Section>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const removeReturn = (value: string): string => {

return value
.replace(/\r/g, "")
.replace(/\n/g, "")
.replace(/\r\n/g, "");
};
export default removeReturn;
1 change: 1 addition & 0 deletions src/sections/character-counter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Counter } from "./Counter/Counter";
Loading

0 comments on commit d756ffc

Please sign in to comment.