From 20cca058b185e56488b32043c230b56c9495dcb5 Mon Sep 17 00:00:00 2001 From: binger_404 <194959593@qq.com> Date: Mon, 15 Aug 2022 22:05:25 +0800 Subject: [PATCH 1/6] add unix-time-converter --- web-src/src/app/consts/tool-sider-configs.tsx | 105 +++-- .../app/tool-blocks/unix-time-converter.scss | 0 .../app/tool-blocks/unix-time-converter.tsx | 196 +++++++++ web-src/src/app/tool-blocks/url-parser.tsx | 415 +++++++++--------- web-src/src/utils/calendar.js | 392 +++++++++++++++++ 5 files changed, 856 insertions(+), 252 deletions(-) create mode 100644 web-src/src/app/tool-blocks/unix-time-converter.scss create mode 100644 web-src/src/app/tool-blocks/unix-time-converter.tsx create mode 100644 web-src/src/utils/calendar.js diff --git a/web-src/src/app/consts/tool-sider-configs.tsx b/web-src/src/app/consts/tool-sider-configs.tsx index f5c738b..b5e55bd 100644 --- a/web-src/src/app/consts/tool-sider-configs.tsx +++ b/web-src/src/app/consts/tool-sider-configs.tsx @@ -1,50 +1,65 @@ -import { NavItemProps } from "@douyinfe/semi-ui/lib/es/navigation"; -import { Calendar, CodeBrackets, LinkOne, PayCode } from "@icon-park/react"; -import { ReactNode } from "react"; -import { JsonFormatterBlock } from "../tool-blocks/json-formatter"; -import { Icon } from "@douyinfe/semi-ui"; -import { Base64Serde } from "../tool-blocks/base64serde"; -import { UrlParser } from "../tool-blocks/url-parser"; -import { CrontabParserBlock } from "../tool-blocks/crontab-parser"; +import { NavItemProps } from '@douyinfe/semi-ui/lib/es/navigation' +import { + Calendar, + CodeBrackets, + LinkOne, + PayCode, + Time, +} from '@icon-park/react' +import { ReactNode } from 'react' +import { JsonFormatterBlock } from '../tool-blocks/json-formatter' +import { Icon } from '@douyinfe/semi-ui' +import { Base64Serde } from '../tool-blocks/base64serde' +import { UrlParser } from '../tool-blocks/url-parser' +import { CrontabParserBlock } from '../tool-blocks/crontab-parser' +import { UnixTimeConverterPage } from '../tool-blocks/unix-time-converter' type ToolSiderItem = { - navItemProps: NavItemProps; - node: ReactNode; -}; + navItemProps: NavItemProps + node: ReactNode +} const ToolSiderConfigs: { [key: string]: ToolSiderItem } = { - "json-formatter": { - navItemProps: { - itemKey: "json-formatter", - text: "JSON Formatter", - icon: } />, - }, - node: , - }, - "base64-serde": { - navItemProps: { - itemKey: "base64-serde", - text: "Base64 Coders", - icon: } />, - }, - node: , - }, - "url-parser": { - navItemProps: { - itemKey: "url-parser", - text: "URL Parser", - icon: } />, - }, - node: , - }, - "crontab-parser": { - navItemProps: { - itemKey: "crontab-parser", - text: "Crontab Parser", - icon: } />, - }, - node: , - } -}; + 'json-formatter': { + navItemProps: { + itemKey: 'json-formatter', + text: 'JSON Formatter', + icon: } />, + }, + node: , + }, + 'base64-serde': { + navItemProps: { + itemKey: 'base64-serde', + text: 'Base64 Coders', + icon: } />, + }, + node: , + }, + 'url-parser': { + navItemProps: { + itemKey: 'url-parser', + text: 'URL Parser', + icon: } />, + }, + node: , + }, + 'crontab-parser': { + navItemProps: { + itemKey: 'crontab-parser', + text: 'Crontab Parser', + icon: } />, + }, + node: , + }, + 'unix-time-converter': { + navItemProps: { + itemKey: 'unix-time-converter', + text: 'Unix Time Converter', + icon: } />, + }, + node: , + }, +} -export default ToolSiderConfigs; +export default ToolSiderConfigs diff --git a/web-src/src/app/tool-blocks/unix-time-converter.scss b/web-src/src/app/tool-blocks/unix-time-converter.scss new file mode 100644 index 0000000..e69de29 diff --git a/web-src/src/app/tool-blocks/unix-time-converter.tsx b/web-src/src/app/tool-blocks/unix-time-converter.tsx new file mode 100644 index 0000000..c9f68be --- /dev/null +++ b/web-src/src/app/tool-blocks/unix-time-converter.tsx @@ -0,0 +1,196 @@ +import { BaseFormApi } from '@douyinfe/semi-foundation/lib/es/form/interface' +import { IconCopy } from '@douyinfe/semi-icons' +import { + Button, + Card, + Col, + DatePicker, + Form, + Input, + Row, + Space, + TimePicker, + Toast, + Typography, +} from '@douyinfe/semi-ui' +import Label from '@douyinfe/semi-ui/lib/es/form/label' +import React, { useRef, useState } from 'react' +import useClipboard from 'use-clipboard-hook' +import { isTauriAppContext } from '../../App' +import { calendar, theDay, theWeek, isLeap } from '../../utils/calendar' + +export const UnixTimeConverterPage = () => { + const [curDate, setCurDate] = useState(new Date()) + const formApi = useRef>() + const { copy } = useClipboard({ + onSuccess: (_) => { + Toast.success('已复制') + }, + }) + + const itemStyle = { width: '90%' } + + const renderLabelText = (text: String, field: string) => { + return ( + + {text} + - - - - - { - setInValue(v) - }} - placeholder="Input/Paste URL here ..." - /> - - - - - - - {parsedUrl?.protocol ?? ' - '} - - {parsedUrl?.port ? ( - - {parsedUrl?.port ?? ' - '} - - ) : ( - <> - )} - - {parsedUrl?.resource ?? ' - '} - - - {parsedUrl?.pathname ?? ' - '} - - {parsedUrl?.user ? ( - - {parsedUrl?.user ?? ' - '} - - ) : ( - <> - )} - {parsedUrl?.hash ? ( - - {parsedUrl?.hash ?? ' - '} - - ) : ( - <> - )} - - {' '} - {parsedUrl?.search ?? ' - '}{' '} - - - - - - - - - {/* + + + + + + + + + { + setInValue(v) + }} + placeholder="Input/Paste URL here ..." + /> + + + + + + + {parsedUrl?.protocol ?? ' - '} + + {parsedUrl?.port ? ( + + {parsedUrl?.port ?? ' - '} + + ) : ( + <> + )} + + {parsedUrl?.resource ?? ' - '} + + + {parsedUrl?.pathname ?? ' - '} + + {parsedUrl?.user ? ( + + {parsedUrl?.user ?? ' - '} + + ) : ( + <> + )} + {parsedUrl?.hash ? ( + + {parsedUrl?.hash ?? ' - '} + + ) : ( + <> + )} + + {' '} + {parsedUrl?.search ?? ' - '}{' '} + + + + + + + + + */} - - - - - ) + /> + + + + + ) } diff --git a/web-src/src/utils/calendar.js b/web-src/src/utils/calendar.js new file mode 100644 index 0000000..fb0a4a1 --- /dev/null +++ b/web-src/src/utils/calendar.js @@ -0,0 +1,392 @@ +function calendar(idate = new Date()) { + const calendar = { + gregorianYear: null, //公历年 + gregorianMonth: null, //公历月 + gregorianDay: null, //公历日 + weekday: null, //星期 + hours: null, + minutes: null, + seconds: null, + + lunarYear: null, //农历年 + lunarMonth: null, //农历月 + lunarDay: null, //农历日 + + lunarYearCn: '', //农历天干地支纪年 + lunarMonthCn: '', //农历中文月 + lunarDayCn: '', //农历中文日 + zodiacYear: '', //农历生肖年 + + solarTerm: '', //节气 + gregorianFestival: '', //公历节日 + lunarFestival: '', //农历节日 + } + + let lunarInfo = [ + 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, + 0x09ad0, 0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, + 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, + 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566, 0x0d4a0, + 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, + 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, + 0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, + 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, + 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, + 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, + 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, + 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, + 0x055c0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, + 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, + 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, + 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, + 0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, + 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, + 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, + ] + + let zodiacs = [ + '鼠', + '牛', + '虎', + '兔', + '龙', + '蛇', + '马', + '羊', + '猴', + '鸡', + '狗', + '猪', + ] + let Gan = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'] + let Zhi = [ + '子', + '丑', + '寅', + '卯', + '辰', + '巳', + '午', + '未', + '申', + '酉', + '戌', + '亥', + ] + let weekday = [ + '星期一', + '星期二', + '星期三', + '星期四', + '星期五', + '星期六', + '星期日', + ] + let now = idate + + //用于计算农历年月日的数据 + let GY = now.getFullYear() + let GM = now.getMonth() + let GD = now.getDate() + + let year = now.getFullYear() + let month = now.getMonth() + 1 + let date = now.getDate() + let hours = now.getHours() + let minutes = now.getMinutes() + let seconds = now.getSeconds() + month = month.toString().padStart(2, '0') + date = date.toString().padStart(2, '0') + hours = hours.toString().padStart(2, '0') + minutes = minutes.toString().padStart(2, '0') + seconds = seconds.toString().padStart(2, '0') + + //==== 传入 offset 传回干支, 0=甲子 + function cyclical(num) { + return Gan[num % 10] + Zhi[num % 12] + } + + //==== 传回农历 year年的总天数 + function lYearDays(year) { + let i, + sum = 348 + for (i = 0x8000; i > 0x8; i >>= 1) { + sum += lunarInfo[year - 1900] & i ? 1 : 0 + } + return sum + leapDays(year) + } + + //==== 传回农历 year年闰月的天数 + function leapDays(year) { + if (leapMonth(year)) { + return lunarInfo[year - 1900] & 0x10000 ? 30 : 29 + } else { + return 0 + } + } + + //==== 传回农历 year年闰哪个月 1-12 , 没闰传回 0 + function leapMonth(year) { + return lunarInfo[year - 1900] & 0xf + } + + //==== 传回农历 year年month月的总天数 + function monthDays(year, month) { + return lunarInfo[year - 1900] & (0x10000 >> month) ? 30 : 29 + } + + //==== 算出农历, 传入日期对象, 传回农历日期对象 + // 该对象属性有 农历年year 农历月month 农历日day 是否闰年isLeap yearCyl dayCyl monCyl + function Lunar(objDate) { + let i, + temp = 0 + let baseDate = new Date(1900, 0, 31) + let offset = Math.floor((objDate - baseDate) / 86400000) + + let dayCyl = offset + 40 + let monCyl = 14 + + for (i = 1900; i < 2050 && offset > 0; i++) { + temp = lYearDays(i) + offset -= temp + monCyl += 12 + } + if (offset < 0) { + offset += temp + i-- + monCyl -= 12 + } + //农历年 + let year = i + let yearCyl = i - 1864 + + let leap = leapMonth(i) //闰哪个月 + let isLeap = false //是否闰年 + + for (i = 1; i < 13 && offset > 0; i++) { + //闰月 + if (leap > 0 && i === leap + 1 && isLeap === false) { + --i + isLeap = true + temp = leapDays(year) + } else { + temp = monthDays(year, i) + } + + //解除闰月 + if (isLeap === true && i === leap + 1) { + isLeap = false + } + + offset -= temp + if (isLeap === false) { + monCyl++ + } + } + + if (offset === 0 && leap > 0 && i === leap + 1) + if (isLeap) { + isLeap = false + } else { + isLeap = true + --i + --monCyl + } + + if (offset < 0) { + offset += temp + --i + --monCyl + } + //农历月 + let month = i + //农历日 + let day = offset + 1 + + return { + year: year, + month: month, + day: day, + isLeap: isLeap, + leap: leap, + yearCyl: yearCyl, + dayCyl: dayCyl, + monCyl: monCyl, + } + } + + //==== 中文日期 m为传入月份,d为传入日期 + function cDay(m, d) { + let nStr1 = [ + '日', + '一', + '二', + '三', + '四', + '五', + '六', + '七', + '八', + '九', + '十', + ] + let nStr2 = ['初', '十', '廿', '卅', ''] + //农历中文月 + let lunarMonthCn + //农历中文日 + let lunarDayCn + if (m > 10) { + lunarMonthCn = '十' + nStr1[m - 10] + } else { + lunarMonthCn = nStr1[m] + } + lunarMonthCn += '月' + + switch (d) { + case 10: + lunarDayCn = '初十' + break + case 20: + lunarDayCn = '二十' + break + case 30: + lunarDayCn = '三十' + break + default: + lunarDayCn = nStr2[Math.floor(d / 10)] + nStr1[d % 10] + } + return { + lunarMonthCn: lunarMonthCn, + lunarDayCn: lunarDayCn, + } + } + + //节气 + function getSolarTerm() { + let sTermInfo = [ + 0, 21208, 42467, 63836, 85337, 107014, 128867, 150921, 173149, 195551, + 218072, 240693, 263343, 285989, 308563, 331033, 353350, 375494, 397447, + 419210, 440795, 462224, 483532, 504758, + ] + let solarTerm = [ + '小寒', + '大寒', + '立春', + '雨水', + '惊蛰', + '春分', + '清明', + '谷雨', + '立夏', + '小满', + '芒种', + '夏至', + '小暑', + '大暑', + '立秋', + '处暑', + '白露', + '秋分', + '寒露', + '霜降', + '立冬', + '小雪', + '大雪', + '冬至', + ] + + let solarTerms = '' + let tmp1 = new Date( + 31556925974.7 * (GY - 1900) + + sTermInfo[GM * 2 + 1] * 60000 + + Date.UTC(1900, 0, 6, 2, 5) + ) + let tmp2 = tmp1.getUTCDate() + if (tmp2 === GD) solarTerms = solarTerm[GM * 2 + 1] + tmp1 = new Date( + 31556925974.7 * (GY - 1900) + + sTermInfo[GM * 2] * 60000 + + Date.UTC(1900, 0, 6, 2, 5) + ) + tmp2 = tmp1.getUTCDate() + if (tmp2 === GD) solarTerms = solarTerm[GM * 2] + + return solarTerms + } + + //公历年月日、星期、时分秒 + calendar.gregorianYear = year + calendar.gregorianMonth = month + calendar.gregorianDay = date + calendar.weekday = weekday[now.getDay()] + calendar.hours = hours + calendar.minutes = minutes + calendar.seconds = seconds + + //去掉时分秒的日期 + let sDObj = new Date(GY, GM, GD) + let lDObj = new Lunar(sDObj) + + //农历年月日、生肖年 + calendar.lunarYear = lDObj.year + calendar.lunarMonth = lDObj.month + calendar.lunarDay = lDObj.day + calendar.zodiacYear = zodiacs[(GY - 4) % 12] + + //农历中文年月日 + calendar.lunarYearCn = cyclical(GY - 1900 + 36) + calendar.lunarMonthCn = cDay(lDObj.month, lDObj.day).lunarMonthCn + calendar.lunarDayCn = cDay(lDObj.month, lDObj.day).lunarDayCn + + //节气 + calendar.solarTerm = getSolarTerm() + + return calendar +} + +function theDay(date) { + return Math.ceil( + (date - new Date(date.getFullYear().toString())) / (24 * 60 * 60 * 1000) + 1 + ) +} + +function theWeek(now) { + var totalDays = 0, + years = now.getYear() + if (years < 1000) years += 1900 + var days = new Array(12) + days[0] = 31 + days[2] = 31 + days[3] = 30 + days[4] = 31 + days[5] = 30 + days[6] = 31 + days[7] = 31 + days[8] = 30 + days[9] = 31 + days[10] = 30 + days[11] = 31 + //判断是否为闰年,针对2月的天数进行计算 + if (Math.round(now.getYear() / 4) == now.getYear() / 4) { + days[1] = 29 + } else { + days[1] = 28 + } + if (now.getMonth() == 0) { + totalDays = totalDays + now.getDate() + } else { + var curMonth = now.getMonth() + for (var count = 1; count <= curMonth; count++) { + totalDays = totalDays + days[count - 1] + } + totalDays = totalDays + now.getDate() + } + //得到第几周 + var week = Math.round(totalDays / 7) + return week +} +function isLeap(now) { + return Math.round(now.getYear() / 4) == now.getYear() / 4 +} + +export { calendar, theDay, theWeek, isLeap } From fb90575fc1dca5153c5d9c0310d07ed14393af7b Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 16 Aug 2022 01:21:25 +0800 Subject: [PATCH 2/6] translations; --- .../app/tool-blocks/unix-time-converter.tsx | 358 +++++++++--------- 1 file changed, 179 insertions(+), 179 deletions(-) diff --git a/web-src/src/app/tool-blocks/unix-time-converter.tsx b/web-src/src/app/tool-blocks/unix-time-converter.tsx index c9f68be..1338545 100644 --- a/web-src/src/app/tool-blocks/unix-time-converter.tsx +++ b/web-src/src/app/tool-blocks/unix-time-converter.tsx @@ -1,17 +1,17 @@ import { BaseFormApi } from '@douyinfe/semi-foundation/lib/es/form/interface' import { IconCopy } from '@douyinfe/semi-icons' import { - Button, - Card, - Col, - DatePicker, - Form, - Input, - Row, - Space, - TimePicker, - Toast, - Typography, + Button, + Card, + Col, + DatePicker, + Form, + Input, + Row, + Space, + TimePicker, + Toast, + Typography, } from '@douyinfe/semi-ui' import Label from '@douyinfe/semi-ui/lib/es/form/label' import React, { useRef, useState } from 'react' @@ -20,177 +20,177 @@ import { isTauriAppContext } from '../../App' import { calendar, theDay, theWeek, isLeap } from '../../utils/calendar' export const UnixTimeConverterPage = () => { - const [curDate, setCurDate] = useState(new Date()) - const formApi = useRef>() - const { copy } = useClipboard({ - onSuccess: (_) => { - Toast.success('已复制') - }, - }) + const [curDate, setCurDate] = useState(new Date()) + const formApi = useRef>() + const { copy } = useClipboard({ + onSuccess: (_) => { + Toast.success('copied content!') + }, + }) - const itemStyle = { width: '90%' } + const itemStyle = { width: '90%' } - const renderLabelText = (text: String, field: string) => { - return ( - - {text} - - - - - - { - setInValue(v) - }} - placeholder="Input/Paste URL here ..." - /> - - - - - - - {parsedUrl?.protocol ?? ' - '} - - {parsedUrl?.port ? ( - - {parsedUrl?.port ?? ' - '} - - ) : ( - <> - )} - - {parsedUrl?.resource ?? ' - '} - - - {parsedUrl?.pathname ?? ' - '} - - {parsedUrl?.user ? ( - - {parsedUrl?.user ?? ' - '} - - ) : ( - <> - )} - {parsedUrl?.hash ? ( - - {parsedUrl?.hash ?? ' - '} - - ) : ( - <> - )} - - {' '} - {parsedUrl?.search ?? ' - '}{' '} - - - - - - - - - - - - - - ) + return ( + + + + + + + + + + { + setInValue(v) + }} + placeholder="Input/Paste URL here ..." + /> + + + + + + + {parsedUrl?.protocol ?? ' - '} + + {parsedUrl?.port ? ( + + {parsedUrl?.port ?? ' - '} + + ) : ( + <> + )} + + {parsedUrl?.resource ?? ' - '} + + + {parsedUrl?.pathname ?? ' - '} + + {parsedUrl?.user ? ( + + {parsedUrl?.user ?? ' - '} + + ) : ( + <> + )} + {parsedUrl?.hash ? ( + + {parsedUrl?.hash ?? ' - '} + + ) : ( + <> + )} + + {' '} + {parsedUrl?.search ?? ' - '}{' '} + + + + + + + + + + + + + + ) } From 98f08052c1fa8178252a7b568e51571d1cbb3afa Mon Sep 17 00:00:00 2001 From: binger_404 <194959593@qq.com> Date: Sat, 20 Aug 2022 19:10:51 +0800 Subject: [PATCH 4/6] change unix-time-converter & add url-encode --- web-src/src/app/consts/tool-sider-configs.tsx | 10 + .../app/tool-blocks/unix-time-converter.tsx | 423 ++++++++++-------- web-src/src/app/tool-blocks/url-encode.scss | 18 + web-src/src/app/tool-blocks/url-encode.tsx | 131 ++++++ web-src/src/app/wigetds/autofit-textarea.tsx | 109 ++--- web-src/src/utils/calendar.js | 47 +- 6 files changed, 473 insertions(+), 265 deletions(-) create mode 100644 web-src/src/app/tool-blocks/url-encode.scss create mode 100644 web-src/src/app/tool-blocks/url-encode.tsx diff --git a/web-src/src/app/consts/tool-sider-configs.tsx b/web-src/src/app/consts/tool-sider-configs.tsx index b5e55bd..a9ad197 100644 --- a/web-src/src/app/consts/tool-sider-configs.tsx +++ b/web-src/src/app/consts/tool-sider-configs.tsx @@ -4,6 +4,7 @@ import { CodeBrackets, LinkOne, PayCode, + Percentage, Time, } from '@icon-park/react' import { ReactNode } from 'react' @@ -13,6 +14,7 @@ import { Base64Serde } from '../tool-blocks/base64serde' import { UrlParser } from '../tool-blocks/url-parser' import { CrontabParserBlock } from '../tool-blocks/crontab-parser' import { UnixTimeConverterPage } from '../tool-blocks/unix-time-converter' +import { UrlEncodePage } from '../tool-blocks/url-encode' type ToolSiderItem = { navItemProps: NavItemProps @@ -60,6 +62,14 @@ const ToolSiderConfigs: { [key: string]: ToolSiderItem } = { }, node: , }, + 'url-encode': { + navItemProps: { + itemKey: 'url-encode', + text: 'URL Encode/Decode', + icon: } />, + }, + node: , + }, } export default ToolSiderConfigs diff --git a/web-src/src/app/tool-blocks/unix-time-converter.tsx b/web-src/src/app/tool-blocks/unix-time-converter.tsx index 1338545..23cfcf6 100644 --- a/web-src/src/app/tool-blocks/unix-time-converter.tsx +++ b/web-src/src/app/tool-blocks/unix-time-converter.tsx @@ -1,196 +1,259 @@ import { BaseFormApi } from '@douyinfe/semi-foundation/lib/es/form/interface' import { IconCopy } from '@douyinfe/semi-icons' import { - Button, - Card, - Col, - DatePicker, - Form, - Input, - Row, - Space, - TimePicker, - Toast, - Typography, + Button, + Card, + Col, + DatePicker, + Form, + Input, + InputGroup, + Row, + Select, + Space, + TimePicker, + Toast, + Typography, } from '@douyinfe/semi-ui' import Label from '@douyinfe/semi-ui/lib/es/form/label' -import React, { useRef, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import useClipboard from 'use-clipboard-hook' import { isTauriAppContext } from '../../App' import { calendar, theDay, theWeek, isLeap } from '../../utils/calendar' export const UnixTimeConverterPage = () => { - const [curDate, setCurDate] = useState(new Date()) - const formApi = useRef>() - const { copy } = useClipboard({ - onSuccess: (_) => { - Toast.success('copied content!') - }, - }) + const [dateType, setDateType] = useState('ms') + const [curDate, setCurDate] = useState(new Date()) + const [nowDate, setNowDate] = useState(new Date()) + const formApi = useRef>() + const { copy } = useClipboard({ + onSuccess: (_) => { + Toast.success('copied content!') + }, + }) - const itemStyle = { width: '90%' } + const itemStyle = { width: '90%' } - const renderLabelText = (text: String, field: string) => { - return ( - - {text} - + + + +
+ { + setCurType(e.target.value) + }} + value={curType} + > + {typeRadios.map((item, index) => { + return {item} + })} + +
+ +
+ { + setInputValue(value) + }} + > +
+
+ + Output: + + + +
+
+ +
+ + )} + + ) +} diff --git a/web-src/src/app/wigetds/autofit-textarea.tsx b/web-src/src/app/wigetds/autofit-textarea.tsx index 84667d0..9522fd9 100644 --- a/web-src/src/app/wigetds/autofit-textarea.tsx +++ b/web-src/src/app/wigetds/autofit-textarea.tsx @@ -1,57 +1,64 @@ -import * as React from 'react'; -import {ForwardedRef, Ref, useEffect} from 'react'; -import {Spin, TextArea} from "@douyinfe/semi-ui"; -import "./autofit-textarea.scss" -import {useObservableState} from "observable-hooks"; +import * as React from 'react' +import { ForwardedRef, Ref, useEffect } from 'react' +import { Spin, TextArea } from '@douyinfe/semi-ui' +import './autofit-textarea.scss' +import { useObservableState } from 'observable-hooks' type Props = { - placeholder?: string - forwardedRef?: Ref - value?: string, - onChange?: (val: string) => void, - isOnError?: Array - isLoading?: boolean -}; + placeholder?: string + forwardedRef?: Ref + value?: string + onChange?: (val: string) => void + isOnError?: Array + isLoading?: boolean + style?: React.CSSProperties +} const AutoFitTextArea = (props: Props) => { - const [cls, setCls] = useObservableState((obs) => { - return obs - }, "text-area mod-normal") + const [cls, setCls] = useObservableState((obs) => { + return obs + }, 'text-area mod-normal') - const [loading, setLoading] = useObservableState(obs => { - return obs - }, props.isLoading) - useEffect(() => { - // eslint-disable-next-line no-self-compare - if (props.isOnError?.length ?? 0 > 0) { - console.debug('setting error selection color') - setCls("text-area mod-error") - } else { - console.debug("reverting selection color") - setCls("text-area mod-normal") - } - }, [props.isOnError, setCls]) + const [loading, setLoading] = useObservableState( + (obs) => { + return obs + }, + props.isLoading + ) + useEffect(() => { + // eslint-disable-next-line no-self-compare + if (props.isOnError?.length ?? 0 > 0) { + console.debug('setting error selection color') + setCls('text-area mod-error') + } else { + console.debug('reverting selection color') + setCls('text-area mod-normal') + } + }, [props.isOnError, setCls]) - useEffect(() => { - setLoading(props.isLoading) - }, [props.isLoading, setLoading]) - return ( - <> - - { - loading && - - } - - ); -}; + useEffect(() => { + setLoading(props.isLoading) + }, [props.isLoading, setLoading]) + return ( + <> + + {loading && ( + + )} + + ) +} - -export const AutoFitTextAreaWithRef = React.forwardRef((props: Props, ref: ForwardedRef) => { - return -}) \ No newline at end of file +export const AutoFitTextAreaWithRef = React.forwardRef( + (props: Props, ref: ForwardedRef) => { + return + } +) diff --git a/web-src/src/utils/calendar.js b/web-src/src/utils/calendar.js index fb0a4a1..2c71755 100644 --- a/web-src/src/utils/calendar.js +++ b/web-src/src/utils/calendar.js @@ -346,45 +346,24 @@ function calendar(idate = new Date()) { function theDay(date) { return Math.ceil( - (date - new Date(date.getFullYear().toString())) / (24 * 60 * 60 * 1000) + 1 + (new Date(date) - new Date(new Date(date).getFullYear().toString())) / + (24 * 60 * 60 * 1000) + + 1 ) } function theWeek(now) { - var totalDays = 0, - years = now.getYear() - if (years < 1000) years += 1900 - var days = new Array(12) - days[0] = 31 - days[2] = 31 - days[3] = 30 - days[4] = 31 - days[5] = 30 - days[6] = 31 - days[7] = 31 - days[8] = 30 - days[9] = 31 - days[10] = 30 - days[11] = 31 - //判断是否为闰年,针对2月的天数进行计算 - if (Math.round(now.getYear() / 4) == now.getYear() / 4) { - days[1] = 29 - } else { - days[1] = 28 - } - if (now.getMonth() == 0) { - totalDays = totalDays + now.getDate() - } else { - var curMonth = now.getMonth() - for (var count = 1; count <= curMonth; count++) { - totalDays = totalDays + days[count - 1] - } - totalDays = totalDays + now.getDate() - } - //得到第几周 - var week = Math.round(totalDays / 7) - return week + //输入日期是年的第几天 + var days = theDay(now) + //输入日期年的一月一日是周几 + var startWeek = new Date( + new Date(now).getFullYear().toString() + '/01/01' + ).getDay() + //输入日期是年的第几周 + var weeks = Math.ceil((days + startWeek - 1) / 7) + return weeks } + function isLeap(now) { return Math.round(now.getYear() / 4) == now.getYear() / 4 } From ce3709093a7b0d4dfe93a28f0dcf9a9cef2d4fb2 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 20 Aug 2022 23:40:15 +0800 Subject: [PATCH 5/6] styles --- .../app/tool-blocks/unix-time-converter.tsx | 139 +++++++++--------- web-src/src/app/tool-blocks/url-encode.tsx | 107 +++++++------- 2 files changed, 124 insertions(+), 122 deletions(-) diff --git a/web-src/src/app/tool-blocks/unix-time-converter.tsx b/web-src/src/app/tool-blocks/unix-time-converter.tsx index 23cfcf6..5769761 100644 --- a/web-src/src/app/tool-blocks/unix-time-converter.tsx +++ b/web-src/src/app/tool-blocks/unix-time-converter.tsx @@ -1,5 +1,5 @@ -import { BaseFormApi } from '@douyinfe/semi-foundation/lib/es/form/interface' -import { IconCopy } from '@douyinfe/semi-icons' +import { BaseFormApi } from "@douyinfe/semi-foundation/lib/es/form/interface"; +import { IconCopy } from "@douyinfe/semi-icons"; import { Button, Card, @@ -14,97 +14,92 @@ import { TimePicker, Toast, Typography, -} from '@douyinfe/semi-ui' -import Label from '@douyinfe/semi-ui/lib/es/form/label' -import React, { useEffect, useRef, useState } from 'react' -import useClipboard from 'use-clipboard-hook' -import { isTauriAppContext } from '../../App' -import { calendar, theDay, theWeek, isLeap } from '../../utils/calendar' +} from "@douyinfe/semi-ui"; +import Label from "@douyinfe/semi-ui/lib/es/form/label"; +import React, { useEffect, useRef, useState } from "react"; +import useClipboard from "use-clipboard-hook"; +import { isTauriAppContext } from "../../App"; +import { calendar, theDay, theWeek, isLeap } from "../../utils/calendar"; export const UnixTimeConverterPage = () => { - const [dateType, setDateType] = useState('ms') - const [curDate, setCurDate] = useState(new Date()) - const [nowDate, setNowDate] = useState(new Date()) - const formApi = useRef>() + const [dateType, setDateType] = useState("ms"); + const [curDate, setCurDate] = useState(new Date()); + const [nowDate, setNowDate] = useState(new Date()); + const formApi = useRef>(); const { copy } = useClipboard({ onSuccess: (_) => { - Toast.success('copied content!') + Toast.success("copied content!"); }, - }) + }); - const itemStyle = { width: '90%' } + const itemStyle = { width: "90%" }; const renderLabelText = (text: String, field: string) => { return (
{text}
- ) - } + ); + }; //是否为Date对象 const isValidDate = (date: any) => { - console.log(date instanceof Date, !isNaN(date.getTime())) - return date instanceof Date && !isNaN(date.getTime()) - } + console.log(date instanceof Date, !isNaN(date.getTime())); + return date instanceof Date && !isNaN(date.getTime()); + }; const setOtherField = ( timestamp: number, curField: string, type = dateType ) => { - let t = timestamp + let t = timestamp; - console.log(t) + console.log(t); - if (type == 's') { - t = Number((t * 1000).toFixed(0)) + if (type == "s") { + t = Number((t * 1000).toFixed(0)); } - const date = new Date(t) + const date = new Date(t); if (isValidDate(date)) { - const setField = curField == 'timestamp' ? 'date' : 'timestamp' - const setValue = setField == 'timestamp' ? String(t) : date - formApi.current?.setValue(setField, setValue) - formApi.current?.setError(curField, '') - setCurDate(date) + const setField = curField == "timestamp" ? "date" : "timestamp"; + const setValue = setField == "timestamp" ? String(t) : date; + formApi.current?.setValue(setField, setValue); + formApi.current?.setError(curField, ""); + setCurDate(date); } else { - formApi.current?.setError(curField, 'Invalid Date') + formApi.current?.setError(curField, "Invalid Date"); } - } + }; const loadNowTime = () => { - const nowTimeStamp = new Date().getTime() - const step = 1000 - (nowTimeStamp % 1000) + const nowTimeStamp = new Date().getTime(); + const step = 1000 - (nowTimeStamp % 1000); setTimeout(() => { - loadNowTime() - setNowDate(new Date(nowTimeStamp + step)) - }, step) - } + loadNowTime(); + setNowDate(new Date(nowTimeStamp + step)); + }, step); + }; useEffect(() => { - loadNowTime() - }, []) + loadNowTime(); + }, []); const presetsTimes = [ { - text: 'Today', + text: "Now", start: new Date(), end: new Date(), }, - { - text: 'Tomorrow', - start: new Date(new Date().valueOf() + 1000 * 3600 * 24), - end: new Date(new Date().valueOf() + 1000 * 3600 * 24), - }, - ] - const { Paragraph } = Typography + ]; + const { Paragraph } = Typography; const { gregorianYear, @@ -118,18 +113,18 @@ export const UnixTimeConverterPage = () => { hours, minutes, seconds, - } = calendar(curDate) + } = calendar(curDate); return ( {(isTauri) => (
(formApi.current = api)} onValueChange={(values, changeValue) => { for (let i in changeValue) { //任意输入为空、全部设置空 if (!changeValue[i]) { - formApi.current?.setValues({}) + formApi.current?.setValues({}); } } }} @@ -138,27 +133,27 @@ export const UnixTimeConverterPage = () => { { - setOtherField(Number(value), 'timestamp') + setOtherField(Number(value), "timestamp"); }} > { - setDateType(value) + setDateType(value); setOtherField( - Number(formApi.current?.getValue('timestamp')), - 'timestamp', + Number(formApi.current?.getValue("timestamp")), + "timestamp", value - ) + ); }} > @@ -172,14 +167,14 @@ export const UnixTimeConverterPage = () => { { if (value && isValidDate(value)) { - setOtherField(new Date(value).getTime(), 'date') + setOtherField(new Date(value).getTime(), "date"); } }} /> @@ -191,7 +186,7 @@ export const UnixTimeConverterPage = () => { Toast.success({ content: 'copied content' }), + onCopy: () => Toast.success({ content: "copied content" }), }} > {nowDate.toString()} @@ -201,7 +196,7 @@ export const UnixTimeConverterPage = () => { Toast.success({ content: 'copied content' }), + onCopy: () => Toast.success({ content: "copied content" }), }} > {curDate.toUTCString()} @@ -211,7 +206,7 @@ export const UnixTimeConverterPage = () => { Toast.success({ content: 'copied content' }), + onCopy: () => Toast.success({ content: "copied content" }), }} > {curDate.toString()} @@ -224,7 +219,7 @@ export const UnixTimeConverterPage = () => { Toast.success({ content: 'copied content' }), + onCopy: () => Toast.success({ content: "copied content" }), }} > {theDay(curDate)} @@ -234,7 +229,7 @@ export const UnixTimeConverterPage = () => { Toast.success({ content: 'copied content' }), + onCopy: () => Toast.success({ content: "copied content" }), }} > {theWeek(curDate)} @@ -244,10 +239,10 @@ export const UnixTimeConverterPage = () => { Toast.success({ content: 'copied content' }), + onCopy: () => Toast.success({ content: "copied content" }), }} > - {isLeap(curDate) ? 'Yes' : 'No'} + {isLeap(curDate) ? "Yes" : "No"} @@ -255,5 +250,5 @@ export const UnixTimeConverterPage = () => { )}
- ) -} + ); +}; diff --git a/web-src/src/app/tool-blocks/url-encode.tsx b/web-src/src/app/tool-blocks/url-encode.tsx index 0b86b83..651074d 100644 --- a/web-src/src/app/tool-blocks/url-encode.tsx +++ b/web-src/src/app/tool-blocks/url-encode.tsx @@ -7,50 +7,56 @@ import { Space, Notification, Toast, -} from '@douyinfe/semi-ui' -import Textarea from '@douyinfe/semi-ui/lib/es/input/textarea' -import { RadioChangeEvent } from '@douyinfe/semi-ui/lib/es/radio' -import { ArrowDown, ArrowUp, Copy, CornerLeftUp } from '@icon-park/react' -import { type } from 'os' -import { useEffect, useState } from 'react' -import useClipboard from 'use-clipboard-hook' -import { isTauriAppContext } from '../../App' -import { AutoFitTextAreaWithRef } from '../wigetds/autofit-textarea' -import './url-encode.scss' + Typography, +} from "@douyinfe/semi-ui"; +import Textarea from "@douyinfe/semi-ui/lib/es/input/textarea"; +import { RadioChangeEvent } from "@douyinfe/semi-ui/lib/es/radio"; +import { ArrowDown, ArrowUp, Copy, CornerLeftUp } from "@icon-park/react"; +import { type } from "os"; +import { useEffect, useState } from "react"; +import useClipboard from "use-clipboard-hook"; +import { isTauriAppContext } from "../../App"; +import { AutoFitTextAreaWithRef } from "../wigetds/autofit-textarea"; +import "./url-encode.scss"; -const exampleString = "abc 0123 !@#$%^&*()|+?<>',.;:`" -const inputPlaceholder = `input` -const outputPlaceholder = `output` +const exampleString = "abc 0123 !@#$%^&*()|+?<>',.;:`"; +const inputPlaceholder = `Input`; +const outputPlaceholder = `Output`; export const UrlEncodePage = () => { - const typeRadios = ['Encode', 'Decode', 'EncodeComponent', 'Decodecomponent'] - const [curType, setCurType] = useState('Encode') - const [outputValue, setOutputValue] = useState('') - const [inputValue, setInputValue] = useState('') + const typeRadios = [ + "Encode", + "Decode", + "Encode Component", + "Decode Component", + ]; + const [curType, setCurType] = useState("Encode"); + const [outputValue, setOutputValue] = useState(""); + const [inputValue, setInputValue] = useState(""); const { copy } = useClipboard({ onSuccess: (_) => { - Toast.success('copied content!') + Toast.success("copied content!"); }, - }) + }); const inputChange = (type: string, value: string) => { try { - if (type === 'Encode') { - setOutputValue(encodeURI(value)) - } else if (type === 'Decode') { - setOutputValue(decodeURI(value)) - } else if (type === 'EncodeComponent') { - setOutputValue(encodeURIComponent(value)) - } else if (type === 'Decodecomponent') { - setOutputValue(decodeURIComponent(value)) + if (type === "Encode") { + setOutputValue(encodeURI(value)); + } else if (type === "Decode") { + setOutputValue(decodeURI(value)); + } else if (type === "Encode Component") { + setOutputValue(encodeURIComponent(value)); + } else if (type === "Decode Component") { + setOutputValue(decodeURIComponent(value)); } } catch (err: any) { - Toast.error({ content: err.toString(), duration: 3 }) - setOutputValue('') + Toast.error({ content: err.toString(), duration: 3 }); + setOutputValue(""); } - } + }; useEffect(() => { - inputChange(curType, inputValue) - }, [inputValue, curType]) + inputChange(curType, inputValue); + }, [inputValue, curType]); return ( {(isTauri) => ( @@ -58,32 +64,36 @@ export const UrlEncodePage = () => {
- input: + Input:
{ - setCurType(e.target.value) + setCurType(e.target.value); }} value={curType} > {typeRadios.map((item, index) => { - return {item} + return ( + + {item} + + ); })}
@@ -93,26 +103,23 @@ export const UrlEncodePage = () => { placeholder={inputPlaceholder} value={inputValue} onChange={(value) => { - setInputValue(value) + setInputValue(value); }} >
- Output: -
)}
- ) -} + ); +}; From a97cbe596ab40de29b378459b126d0bc1ce2f86b Mon Sep 17 00:00:00 2001 From: binger_404 <194959593@qq.com> Date: Sun, 21 Aug 2022 02:36:23 +0800 Subject: [PATCH 6/6] fix: unix-time & url-encode --- web-src/src/app/shared/tools-sider.tsx | 396 ++++++++++-------- .../app/tool-blocks/unix-time-converter.tsx | 248 +++++++---- web-src/src/app/tool-blocks/url-encode.tsx | 95 +++-- web-src/src/utils/calendar.js | 391 ++--------------- 4 files changed, 469 insertions(+), 661 deletions(-) diff --git a/web-src/src/app/shared/tools-sider.tsx b/web-src/src/app/shared/tools-sider.tsx index 062d008..039eeed 100644 --- a/web-src/src/app/shared/tools-sider.tsx +++ b/web-src/src/app/shared/tools-sider.tsx @@ -1,182 +1,218 @@ -import { Button, Input, Nav, Space } from "@douyinfe/semi-ui"; -import { OnSelectedData } from "@douyinfe/semi-ui/lib/es/navigation"; -import React, { useContext, useRef, useState } from "react"; -import ToolSiderConfigs from "../consts/tool-sider-configs"; -import toolSiderConfigs from "../consts/tool-sider-configs"; -import { SharedSubjectContext } from "../context/shared-subjects"; -import { useMount } from "react-use"; -import { useLocation, useSearchParams } from 'react-router-dom'; -import "./tools-sider.scss" -import { useObservableState } from "observable-hooks/dist/esm2015"; -import { GlobalHotKeys } from "react-hotkeys"; -import { IconSetting, IconSidebar } from "@douyinfe/semi-icons"; -import { findDOMNode } from "react-dom"; -import { Pref } from "../context/pref"; -import { SettingsModal } from "./setting"; +import { Button, Input, Nav, Row, Space } from '@douyinfe/semi-ui' +import { OnSelectedData } from '@douyinfe/semi-ui/lib/es/navigation' +import React, { useContext, useRef, useState } from 'react' +import ToolSiderConfigs from '../consts/tool-sider-configs' +import toolSiderConfigs from '../consts/tool-sider-configs' +import { SharedSubjectContext } from '../context/shared-subjects' +import { useMount } from 'react-use' +import { useLocation, useSearchParams } from 'react-router-dom' +import './tools-sider.scss' +import { useObservableState } from 'observable-hooks/dist/esm2015' +import { GlobalHotKeys } from 'react-hotkeys' +import { IconSetting, IconSidebar } from '@douyinfe/semi-icons' +import { findDOMNode } from 'react-dom' +import { Pref } from '../context/pref' +import { SettingsModal } from './setting' export const ToolsSider = () => { - const sharedSubsCtx = useContext(SharedSubjectContext); - const navRef = useRef