优化自定义选择框代码

This commit is contained in:
fzk
2024-12-27 16:11:03 +08:00
parent f62900a185
commit b8d04c5c8f
6 changed files with 158 additions and 73 deletions

View File

@@ -35,6 +35,10 @@ export default function ValidateContent(props) {
}
}
function handleCancel() {
props.handleCancel()
}
function help() {
sendToBackground({
name: "tab",
@@ -45,10 +49,21 @@ export default function ValidateContent(props) {
}
return (
<>
<div
style={{
width: "350px",
padding: "10px",
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
backgroundColor: "white",
borderRadius: "5px",
textAlign: "center"
}}>
{isValid ? (
<p className="valid" style={{ fontSize: "16px", color: "red" }}>
,
</p>
) : (
<>
@@ -60,23 +75,33 @@ export default function ValidateContent(props) {
)
</div>
<div>
<img src={qrcodeUrl} alt="微信公众号" />
<img style={{ margin: "auto" }} src={qrcodeUrl} alt="微信公众号" />
</div>
<Space.Compact style={{ width: "100%" }}>
<div style={{ marginTop: "10px" }}>
<Input
placeholder="输入激活码"
ref={inputRef}
prefix={<KeyOutlined />}
/>
</div>
<div
style={{
marginTop: "10px",
display: "flex",
justifyContent: "space-between"
}}>
<Button
type="primary"
className="valid-submit"
onClick={handleSubmit}>
</Button>
</Space.Compact>
<Button type="primary" onClick={handleCancel}>
</Button>
</div>
</>
)}
</>
</div>
)
}

View File

@@ -1,11 +1,13 @@
import { Modal } from "antd"
import dayjs from "dayjs"
import React, { useEffect, useRef, useState } from "react"
import { createRoot } from "react-dom/client"
import { useMessage } from "@plasmohq/messaging/hook"
import { useStorage } from "@plasmohq/storage/hook"
import { addCss, saveHtml, saveMarkdown, scrollToTop, setIcon } from "~tools"
import ValidateContent from "~component/contents/validateContent"
import { addCss, saveHtml, saveMarkdown } from "~tools"
import { savePdf } from "~utils/downloadPdf"
import { useContent } from "~utils/editMarkdownHook"
import Turndown from "~utils/turndown"
@@ -20,10 +22,10 @@ export default function CustomDomSelector() {
const downloadType = useRef("")
const [content, setContent] = useContent()
const [validTime] = useStorage("app-validTime", "1730390400")
const [isModalOpen, setIsModalOpen] = useState(false)
const selectorRef = useRef<HTMLElement | null>(null)
const tooltipRef = useRef<HTMLElement | null>(null)
const modalRef = useRef<HTMLElement | null>(null)
const articleTitle = document
.querySelector<HTMLElement>("head title")
@@ -31,31 +33,14 @@ export default function CustomDomSelector() {
useEffect(() => {
addEventListeners()
setIcon(true)
addCss(`.codebox-current { outline: 2px solid #42b88350 !important; }`)
return () => {
removeEventListeners()
// removeSelector()
removeTooltip()
removeHighlight()
}
}, [])
const createSelector = () => {
const selector = document.createElement("div")
selector.classList.add("codebox-selector")
selector.style.position = "absolute"
selector.style.pointerEvents = "none"
selector.style.zIndex = "2147483640"
selector.style.backgroundColor = "#42b88325"
selector.style.border = "2px solid #42b88350"
selector.style.borderRadius = "2px"
selector.style.transition = "all 0.1s ease-in"
selector.style.display = "none"
document.body.appendChild(selector)
selectorRef.current = selector
}
const createTooltip = () => {
const tooltip = document.createElement("div")
tooltip.classList.add("codebox-tooltip")
@@ -66,7 +51,6 @@ export default function CustomDomSelector() {
tooltip.style.borderRadius = "5px"
tooltip.style.padding = "8px"
tooltip.style.boxShadow = "0 2px 8px rgba(0, 0, 0, 0.15)"
// tooltip.style.display = "none"
document.body.appendChild(tooltip)
const root = createRoot(tooltip)
root.render(
@@ -79,12 +63,6 @@ export default function CustomDomSelector() {
tooltipRef.current = tooltip
}
const removeSelector = () => {
if (selectorRef.current) {
document.body.removeChild(selectorRef.current)
}
}
const removeTooltip = () => {
if (tooltipRef.current) {
document.body.removeChild(tooltipRef.current)
@@ -106,7 +84,6 @@ export default function CustomDomSelector() {
if (isReady.current && !isSelect.current) {
const target = event.target as HTMLElement
highlightElement(target)
// updateSelectorPosition(target)
}
}
@@ -122,7 +99,6 @@ export default function CustomDomSelector() {
createTooltip()
isSelect.current = true
highlightElement(target)
// updateSelectorPosition(target)
updateTooltipPosition(target)
event.stopPropagation()
event.preventDefault()
@@ -142,17 +118,6 @@ export default function CustomDomSelector() {
selectorRef.current = null
}
const updateSelectorPosition = (element: HTMLElement) => {
if (selectorRef.current) {
const rect = element.getBoundingClientRect()
selectorRef.current.style.top = `${rect.top + window.scrollY}px`
selectorRef.current.style.left = `${rect.left + window.scrollX}px`
selectorRef.current.style.width = `${rect.width}px`
selectorRef.current.style.height = `${rect.height}px`
selectorRef.current.style.display = "block"
}
}
const updateTooltipPosition = (element: HTMLElement) => {
const rect = element.getBoundingClientRect()
const distanceTop = rect.top + window.scrollY
@@ -161,7 +126,7 @@ export default function CustomDomSelector() {
distanceTop < 50 ? distanceTop + rect.height + 5 : distanceTop - 40
tooltipRef.current.style.top = `${top}px`
tooltipRef.current.style.left = `${distanceLeft + 5}px`
scrollToTop(tooltipRef.current)
window.scrollTo({ top: top - 150, behavior: "smooth" })
}
useMessage(async (req: any, res: any) => {
@@ -188,8 +153,9 @@ export default function CustomDomSelector() {
isSelect.current = false
}
const handleConfirm = () => {
const handleOkModal = () => {
if (!selectorRef.current || !downloadType.current) return
switch (downloadType.current) {
case "html":
saveHtml(selectorRef.current, articleTitle)
@@ -207,6 +173,31 @@ export default function CustomDomSelector() {
}
resetState()
setTimeout(() => {
document.body.removeChild(modalRef.current)
modalRef.current = null
}, 1000)
}
const handleConfirm = () => {
const modal = document.createElement("div")
modal.classList.add("codebox-modal")
modal.style.position = "fixed"
modal.style.zIndex = "2147483642"
modal.style.backgroundColor = "rgba(0, 0, 0, 0.7)"
modal.style.width = "100vw"
modal.style.height = "100vh"
modal.style.top = "0"
modal.style.left = "0"
document.body.appendChild(modal)
const root = createRoot(modal)
root.render(
<ValidateContent
handleOk={handleOkModal}
handleCancel={handleCancelModal}
/>
)
modalRef.current = modal
}
const handleCancel = () => {
@@ -215,7 +206,6 @@ export default function CustomDomSelector() {
const resetState = () => {
removeHighlight()
// removeSelector()
removeTooltip()
isReady.current = false
isSelect.current = false
@@ -247,26 +237,10 @@ export default function CustomDomSelector() {
}
}
const handleOkModal = () => {
setIsModalOpen(false)
}
const handleCancelModal = () => {
setIsModalOpen(false)
document.body.removeChild(modalRef.current)
modalRef.current = null
}
return (
<>
<Modal
title="Basic Modal"
className="codebox-modal"
open={isModalOpen}
onOk={handleOkModal}
onCancel={handleCancelModal}>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Modal>
</>
)
return <div style={{ display: "none" }}></div>
}

View File

@@ -22,7 +22,8 @@ export const config: PlasmoCSConfig = {
"https://mp.weixin.qq.com/*",
"https://day.js.org/*",
"https://stackoverflow.com/*",
"https://dev.to/*"
"https://dev.to/*",
"https://greasyfork.org/*"
]
}
@@ -70,7 +71,12 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
const element = anchor.element
const style = window.getComputedStyle(element)
const width = style.getPropertyValue("width")
let width = style.getPropertyValue("width")
if (location.host.includes("greasyfork")) {
const codeContainer = element.closest(".code-container")
width = window.getComputedStyle(codeContainer).getPropertyValue("width")
}
const onCopy = async () => {
try {
@@ -80,9 +86,9 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
let textContent = ""
if (codeBlock) {
textContent = codeBlock.textContent
textContent = codeBlock.innerText
} else {
textContent = preBlock && preBlock.textContent
textContent = preBlock && preBlock.innerText
}
navigator.clipboard.writeText(textContent)

View File

@@ -5,9 +5,17 @@ import type {
PlasmoGetShadowHostId,
PlasmoGetStyle
} from "plasmo"
import { useEffect, useRef, useState } from "react"
import { sendToBackground } from "@plasmohq/messaging"
import { useMessage } from "@plasmohq/messaging/hook"
import { useStorage } from "@plasmohq/storage/hook"
import CustomDomSelector from "~component/customDomSelector"
import { ThemeProvider } from "~theme"
import { setIcon } from "~tools"
import { getSummary } from "~utils/coze"
import DrawImages from "~utils/drawImages"
const HOST_ID = "codebox-csui"
@@ -20,7 +28,79 @@ export const getStyle: PlasmoGetStyle = () => {
return style
}
const articleTitle = document
.querySelector<HTMLElement>("head title")
?.innerText.trim()
export default function CustomOverlay() {
const [summary, setSummary] = useStorage("app-summary", "")
useEffect(() => {
setIcon(true)
}, [])
useMessage(async (req: any, res: any) => {
if (req.name == "app-downloadImages") {
await downloadImages(req.body?.onProgress)
}
if (req.name == "app-get-summary") {
setSummary("")
const res = await getSummary(location.href)
if (res.code == 0) {
const result = JSON.parse(res.data)
setSummary(result)
}
}
if (req.name == "app-full-page-screenshot") {
if (confirm("确认截图?")) {
const { scrollHeight, clientHeight } = document.documentElement
const devicePixelRatio = window.devicePixelRatio || 1
let capturedHeight = 0
let capturedImages = []
const captureAndScroll = async () => {
const scrollAmount = clientHeight * devicePixelRatio
const res = await sendToBackground({ name: "screenshot" })
const dataUrl = res.dataUrl
capturedHeight += scrollAmount
if (capturedHeight < scrollHeight * devicePixelRatio) {
capturedImages.push(dataUrl)
window.scrollTo(0, capturedHeight)
setTimeout(captureAndScroll, 2000) // Adjust the delay as needed
} else {
DrawImages(capturedImages, articleTitle)
}
}
captureAndScroll()
}
}
})
async function downloadImages(
onProgress?: (current: number, total: number) => void
) {
const imageUrls = Array.from(document.images).map((img) => img.src)
try {
const res = await sendToBackground({
name: "download",
body: {
action: "downloadAllImages",
imageUrls: imageUrls,
title: articleTitle,
onProgress: onProgress
}
})
if (res.code == 0) {
alert("下载失败")
}
} catch (error) {
console.error(`Failed to download images:`, error)
}
}
return (
<ThemeProvider>
<StyleProvider container={document.getElementById(HOST_ID).shadowRoot}>

View File

@@ -1,7 +1,7 @@
{
"name": "code-box",
"displayName": "__MSG_extensionName__",
"version": "0.9.24",
"version": "0.9.25",
"description": "__MSG_extensionDescription__",
"author": "027xiguapi. <458813868@qq.com>",
"scripts": {

View File

@@ -5,7 +5,7 @@ import { sendToBackground } from "@plasmohq/messaging"
export function scrollToTop(element) {
window.scrollTo({
top: element.offsetTop + 50,
top: element.offsetTop - 50,
behavior: "smooth" // 可选,平滑滚动
})
}