Skip to content
This repository was archived by the owner on Aug 16, 2024. It is now read-only.

Commit 600f760

Browse files
committed
refactor: use css-in-js
1 parent 92b05f0 commit 600f760

File tree

14 files changed

+159
-404
lines changed

14 files changed

+159
-404
lines changed

.babelrc

+12-17
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,25 @@
44
"@babel/preset-env",
55
{
66
"useBuiltIns": "entry",
7-
"corejs": 3
7+
"corejs": "3.8.2"
88
}
99
],
1010
"@babel/preset-typescript",
11-
"react-app"
11+
[
12+
"@babel/preset-react",
13+
{ "runtime": "automatic", "importSource": "@emotion/react" }
14+
]
1215
],
1316
"plugins": [
17+
"@babel/plugin-proposal-class-properties",
1418
"babel-plugin-transform-inline-environment-variables",
1519
"babel-plugin-macros",
16-
[
17-
"@emotion/babel-plugin-jsx-pragmatic",
18-
{
19-
"export": "jsx",
20-
"import": "__cssprop",
21-
"module": "@emotion/react"
22-
}
23-
],
24-
[
25-
"@babel/plugin-transform-react-jsx",
26-
{
27-
"pragma": "__cssprop",
28-
"pragmaFrag": "React.Fragment"
29-
}
30-
],
20+
["@emotion/babel-plugin", {
21+
"sourceMap": true,
22+
"autoLabel": "dev-only",
23+
"labelFormat": "[local]",
24+
"cssPropOptimization": true
25+
}],
3126
"react-hot-loader/babel"
3227
]
3328
}

package.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,13 @@
2020
"dependencies": {
2121
"@babel/core": "^7.12.10",
2222
"@babel/plugin-proposal-class-properties": "^7.12.1",
23-
"@babel/plugin-transform-react-jsx": "^7.12.12",
2423
"@babel/preset-env": "^7.12.11",
2524
"@babel/preset-react": "^7.12.10",
2625
"@babel/preset-typescript": "^7.12.7",
2726
"@commitlint/cli": "^11.0.0",
2827
"@commitlint/config-angular": "^11.0.0",
2928
"@emotion/babel-plugin": "^11.1.2",
30-
"@emotion/babel-plugin-jsx-pragmatic": "^0.1.5",
29+
"@emotion/cache": "^11.1.3",
3130
"@emotion/css": "^11.1.3",
3231
"@emotion/react": "^11.1.4",
3332
"@emotion/server": "^11.0.0",
@@ -53,7 +52,6 @@
5352
"babel-loader": "^8.2.2",
5453
"babel-plugin-macros": "^3.0.1",
5554
"babel-plugin-transform-inline-environment-variables": "^0.4.3",
56-
"babel-preset-react-app": "^10.0.0",
5755
"chrome-call": "^4.0.1",
5856
"clean-webpack-plugin": "^3.0.0",
5957
"clsx": "^1.1.1",
@@ -97,6 +95,7 @@
9795
"react-scroll-to-bottom": "^4.1.0",
9896
"sass-loader": "^10.1.0",
9997
"scrollparent": "^2.0.1",
98+
"semver": "^7.3.4",
10099
"smoothscroll-polyfill": "^0.4.4",
101100
"source-map-loader": "^1.1.3",
102101
"style-loader": "^2.0.0",

src/components/IconButton.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import React, {
55
ReactNode,
66
Ref,
77
} from 'react'
8-
import clsx from 'clsx'
8+
import tw from 'twin.macro'
99

1010
export interface BaseProps {
1111
children: ReactNode
@@ -26,8 +26,13 @@ const IconButton = forwardRef(function IconButton(
2626
<button
2727
{...props}
2828
ref={ref}
29-
className={clsx(['ate_IconButton', props.className])}
30-
onClick={handleClick}>
29+
onClick={handleClick}
30+
css={tw`
31+
inline-flex justify-center items-center w-auto h-auto m-0 p-2
32+
cursor-pointer text-center no-underline rounded-md
33+
border border-solid border-gray-800 bg-white hover:bg-gray-100 active:bg-gray-200
34+
transition-colors ease-in-out duration-150
35+
`}>
3136
{props.children}
3237
</button>
3338
)

src/pages/Content/common/polyfill.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import smoothScrollPolyfill from 'smoothscroll-polyfill'
2+
3+
if (!('scrollBehavior' in document.documentElement.style)) {
4+
smoothScrollPolyfill.polyfill()
5+
}

src/pages/Content/components/App/index.tsx

+60-28
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import clsx from 'clsx'
2-
import React, { useCallback, useEffect, useMemo, useState } from 'react'
1+
import tw, { css } from 'twin.macro'
2+
import { ClassNames } from '@emotion/react'
3+
import React, { useRef, useCallback, useEffect, useMemo, useState } from 'react'
34
import Draggable, { DraggableEventHandler } from 'react-draggable'
45
import cc from 'chrome-call'
56
// @ts-ignore
@@ -19,6 +20,8 @@ import TranslationList from '../TranslationList'
1920
const App: React.FC = () => {
2021
const [config, setConfig] = useState<ConfigState>()
2122
const [close, setClose] = useState(false)
23+
const appRef = useRef<HTMLDivElement>(null)
24+
const closeButtonRef = useRef<HTMLButtonElement>(null)
2225
const dispatch = useTranslateJobsDispatch()
2326

2427
const appPosition = useMemo(() => {
@@ -53,9 +56,7 @@ const App: React.FC = () => {
5356
const onDragStart: DraggableEventHandler = (e) => {
5457
if (
5558
e.target instanceof Element &&
56-
document
57-
.querySelector<HTMLButtonElement>('.ate_App__close-button')
58-
?.contains(e.target)
59+
closeButtonRef.current?.contains(e.target)
5960
) {
6061
return false
6162
}
@@ -81,30 +82,61 @@ const App: React.FC = () => {
8182

8283
return (
8384
<ConfigContext.Provider value={config}>
84-
<Draggable
85-
handle=".ate_App__header"
86-
onStart={onDragStart}
87-
defaultPosition={appPosition}>
88-
<div className={clsx(['ate_App', close && 'ate_App--inactive'])}>
89-
<SnackbarProvider
90-
maxSnack={3}
91-
domRoot={document.querySelector('.ate_App') as HTMLDivElement}>
92-
<div className="ate_App__header">
93-
<span>A Translator</span>
94-
<span>
95-
<IconButton
96-
className="ate_App__close-button"
97-
onClick={() => setClose(true)}>
98-
<CloseIcon />
99-
</IconButton>
100-
</span>
85+
<ClassNames>
86+
{({ css, cx }) => (
87+
<Draggable
88+
handle=".ate_App__header"
89+
onStart={onDragStart}
90+
defaultPosition={appPosition}>
91+
<div
92+
ref={appRef}
93+
className={cx(
94+
'ate_App',
95+
css`
96+
position: absolute;
97+
width: 450px;
98+
height: 600px;
99+
z-index: 1;
100+
will-change: transform;
101+
102+
${tw`bg-white shadow-md rounded-lg overflow-hidden flex flex-col`}
103+
`,
104+
close &&
105+
css`
106+
display: none;
107+
`,
108+
)}>
109+
<SnackbarProvider
110+
maxSnack={3}
111+
domRoot={appRef.current || undefined}>
112+
<div
113+
className="ate_App__header"
114+
tw="bg-purple-800 px-5 py-3 text-white font-bold text-lg cursor-move flex justify-between items-center">
115+
<span>A Translator</span>
116+
<span>
117+
<IconButton
118+
ref={closeButtonRef}
119+
css={[
120+
tw`p-1`,
121+
css`
122+
svg {
123+
@apply text-gray-800;
124+
}
125+
`,
126+
]}
127+
onClick={() => setClose(true)}>
128+
<CloseIcon />
129+
</IconButton>
130+
</span>
131+
</div>
132+
<ScrollToBottom tw="flex-1 overflow-auto" debug={false}>
133+
<TranslationList />
134+
</ScrollToBottom>
135+
</SnackbarProvider>
101136
</div>
102-
<ScrollToBottom className="ate_App__container" debug={false}>
103-
<TranslationList />
104-
</ScrollToBottom>
105-
</SnackbarProvider>
106-
</div>
107-
</Draggable>
137+
</Draggable>
138+
)}
139+
</ClassNames>
108140
</ConfigContext.Provider>
109141
)
110142
}

src/pages/Content/components/TranslationItem.tsx

+32-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Clipboard from 'react-clipboard.js'
33
import { useSnackbar } from 'notistack'
44
import { Collapse } from 'react-collapse'
55
import scrollParent from 'scrollparent'
6+
import tw, { css } from 'twin.macro'
67

78
import logger from '../../../common/logger'
89
import { TranslateResult } from '../../../common/types'
@@ -96,10 +97,22 @@ const TranslationItem: React.FC<{
9697
}, [job, config])
9798

9899
return (
99-
<div className="ate_TranslationItem">
100-
<div className="ate_TranslationItem__upper">
100+
<div tw="p-3 text-gray-800 space-y-3 select-text">
101+
<div tw="space-y-3">
101102
<div
102-
className="ate_TranslationItem__original"
103+
tw="bg-gray-50 hover:bg-gray-100 p-3 rounded cursor-pointer leading-normal"
104+
css={css`
105+
.ReactCollapse--collapse {
106+
min-height: 48px;
107+
will-change: height;
108+
transition-property: height;
109+
110+
${tw`ease-in-out duration-300`};
111+
}
112+
.ReactCollapse--content {
113+
${tw`space-y-2`};
114+
}
115+
`}
103116
onClick={() => setCollapse((prev) => !prev)}>
104117
<Collapse isOpened={!collapse}>
105118
<>
@@ -111,20 +124,30 @@ const TranslationItem: React.FC<{
111124
</div>
112125

113126
{loading ? (
114-
<div className="ate_TranslationItem__result">翻译中…</div>
127+
<div tw="rounded bg-yellow-50 p-3 space-y-2 leading-normal">
128+
翻译中…
129+
</div>
115130
) : undefined}
116131
{result ? (
117-
<div className="ate_TranslationItem__result">
132+
<div tw="rounded bg-yellow-50 p-3 space-y-2 leading-normal">
118133
{result.map((item, index) => (
119134
<div key={index}>{item}</div>
120135
))}
121136
</div>
122137
) : undefined}
123138
</div>
124-
<div className="ate_TranslationItem__lower">
139+
<div
140+
css={[
141+
tw`flex justify-between items-center`,
142+
css`
143+
& > div {
144+
${tw`space-x-2`}
145+
}
146+
`,
147+
]}>
125148
<div>
126149
{job.sourceLang && (
127-
<div className="ate_TranslationItem__source-lang-tag">
150+
<div tw="px-2 py-1 bg-green-50 text-green-600 text-sm rounded">
128151
{job.sourceLang}
129152
</div>
130153
)}
@@ -136,12 +159,12 @@ const TranslationItem: React.FC<{
136159
button-title="复制翻译结果"
137160
onSuccess={() => enqueueSnackbar('复制成功')}
138161
component={IconButton}
139-
className="ate_TranslationItem__copy-button">
162+
tw="p-1">
140163
<ClipboardCopy />
141164
</Clipboard>
142165
) : undefined}
143166
<IconButton
144-
className="ate_TranslationItem__jump-button"
167+
tw="p-1"
145168
onClick={() => findOriginal()}
146169
title="跳转到原文">
147170
<ArrowRight />

src/pages/Content/components/TranslationList/index.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react'
2+
import tw from 'twin.macro'
23

34
import { useTranslateJobs } from '../../providers/translate-jobs'
45
import TranslationItem from '../TranslationItem'
@@ -7,13 +8,13 @@ const TranslationList: React.FC = () => {
78
const jobsState = useTranslateJobs()
89

910
return (
10-
<div className="ate_TranslationList">
11+
<div tw="divide-y divide-gray-200 divide-solid">
1112
{!jobsState.jobs.length ? (
12-
<div className="ate_TranslationList__empty">还没有翻译…</div>
13+
<div tw="py-2 text-center text-gray-500">还没有翻译…</div>
1314
) : undefined}
1415

1516
{jobsState.jobs.map((job) => (
16-
<div key={job.id} className="ate_TranslationList__item">
17+
<div key={job.id} tw="border-l-0 border-r-0">
1718
<TranslationItem job={job} />
1819
</div>
1920
))}

src/pages/Content/index.tsx

+16-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
import './common/polyfill'
2+
13
import React from 'react'
24
import { render } from 'react-dom'
35
import { v4 as uuid } from 'uuid'
4-
import smoothScrollPolyfill from 'smoothscroll-polyfill'
6+
import createCache from '@emotion/cache'
7+
import { CacheProvider } from '@emotion/react'
8+
9+
import './styles/index.scss'
510

611
import logger from '../../common/logger'
712
import rangy from '../../common/rangy'
@@ -10,7 +15,6 @@ import translationStack from './common/translation-stack'
1015
import { TextSelection, TranslateJob } from './common/types'
1116
import { getDocumentLang, getFirstRange } from './common/utils'
1217
import App from './components/App'
13-
import './styles/index.scss'
1418
import { TranslateJobsProvider } from './providers/translate-jobs'
1519

1620
let isAppAttached = false
@@ -56,10 +60,6 @@ const main = async () => {
5660
})
5761
}
5862
})
59-
60-
if (!('scrollBehavior' in document.documentElement.style)) {
61-
smoothScrollPolyfill.polyfill()
62-
}
6363
}
6464

6565
const onMouseUp = (e: MouseEvent) => {
@@ -200,14 +200,20 @@ const getTextSelection = (selection: RangySelection): TextSelection => {
200200
}
201201
}
202202

203-
const initApp = () => {
203+
const styleCache = createCache({
204+
key: 'ate',
205+
})
206+
207+
const initApp = (): void => {
204208
if (isAppAttached) {
205209
window.__ate_setClose && window.__ate_setClose(false)
206210
} else {
207211
render(
208-
<TranslateJobsProvider>
209-
<App />
210-
</TranslateJobsProvider>,
212+
<CacheProvider value={styleCache}>
213+
<TranslateJobsProvider>
214+
<App />
215+
</TranslateJobsProvider>
216+
</CacheProvider>,
211217
document.querySelector('#ate-container'),
212218
)
213219
isAppAttached = true

0 commit comments

Comments
 (0)