mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 21:14:21 +08:00
合并冲突
This commit is contained in:
+2
-7
@@ -250,9 +250,7 @@ function MainContent(): React.JSX.Element {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleOAuthUserUpdated = (
|
const handleOAuthUserUpdated = (event: Event) => {
|
||||||
event: Event
|
|
||||||
) => {
|
|
||||||
const customEvent = event as CustomEvent<{
|
const customEvent = event as CustomEvent<{
|
||||||
user?: { name?: string } | null
|
user?: { name?: string } | null
|
||||||
}>
|
}>
|
||||||
@@ -267,10 +265,7 @@ function MainContent(): React.JSX.Element {
|
|||||||
|
|
||||||
window.addEventListener("ss:oauth-user-updated", handleOAuthUserUpdated as EventListener)
|
window.addEventListener("ss:oauth-user-updated", handleOAuthUserUpdated as EventListener)
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener(
|
window.removeEventListener("ss:oauth-user-updated", handleOAuthUserUpdated as EventListener)
|
||||||
"ss:oauth-user-updated",
|
|
||||||
handleOAuthUserUpdated as EventListener
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}, [refreshPermissionFromAuth])
|
}, [refreshPermissionFromAuth])
|
||||||
|
|
||||||
|
|||||||
@@ -862,9 +862,9 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
? "repeat(auto-fill, minmax(102px, 1fr))"
|
? "repeat(auto-fill, minmax(102px, 1fr))"
|
||||||
: list.viewMode === "largeAvatar"
|
: list.viewMode === "largeAvatar"
|
||||||
? "repeat(auto-fill, minmax(180px, 1fr))"
|
? "repeat(auto-fill, minmax(180px, 1fr))"
|
||||||
: list.viewMode === "list"
|
: list.viewMode === "list"
|
||||||
? "1fr"
|
? "1fr"
|
||||||
: "repeat(auto-fill, minmax(220px, 1fr))",
|
: "repeat(auto-fill, minmax(220px, 1fr))",
|
||||||
gap: 12,
|
gap: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -941,9 +941,9 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
? "8px"
|
? "8px"
|
||||||
: list.viewMode === "largeAvatar"
|
: list.viewMode === "largeAvatar"
|
||||||
? 0
|
? 0
|
||||||
: list.viewMode === "list"
|
: list.viewMode === "list"
|
||||||
? "10px 12px"
|
? "10px 12px"
|
||||||
: "12px 14px",
|
: "12px 14px",
|
||||||
height:
|
height:
|
||||||
list.viewMode === "grid" || list.viewMode === "largeAvatar"
|
list.viewMode === "grid" || list.viewMode === "largeAvatar"
|
||||||
? "100%"
|
? "100%"
|
||||||
@@ -1108,9 +1108,7 @@ ORDER BY reward_points DESC, score DESC`,
|
|||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
color:
|
color:
|
||||||
primaryMetric && primaryMetric.value >= 0
|
primaryMetric && primaryMetric.value >= 0 ? "#52c41a" : "#ff4d4f",
|
||||||
? "#52c41a"
|
|
||||||
: "#ff4d4f",
|
|
||||||
background: "rgba(255,255,255,0.62)",
|
background: "rgba(255,255,255,0.62)",
|
||||||
border: "1px solid rgba(255,255,255,0.82)",
|
border: "1px solid rgba(255,255,255,0.82)",
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export function ContentArea({
|
|||||||
: permission === "points"
|
: permission === "points"
|
||||||
? t("permissions.points")
|
? t("permissions.points")
|
||||||
: t("permissions.view")}
|
: t("permissions.view")}
|
||||||
</Tag>
|
</Tag>
|
||||||
)
|
)
|
||||||
const fallbackDisplayName =
|
const fallbackDisplayName =
|
||||||
permission === "admin"
|
permission === "admin"
|
||||||
@@ -371,7 +371,9 @@ export function ContentArea({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ fontSize: "12px", color: "var(--ss-text-secondary)" }}>最近同步时间</div>
|
<div style={{ fontSize: "12px", color: "var(--ss-text-secondary)" }}>最近同步时间</div>
|
||||||
<div style={{ fontSize: "12px", color: "var(--ss-text-main)" }}>{formattedLastSyncTime}</div>
|
<div style={{ fontSize: "12px", color: "var(--ss-text-main)" }}>
|
||||||
|
{formattedLastSyncTime}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "13px", color: "var(--ss-text-secondary)" }}>云空间用量</div>
|
<div style={{ fontSize: "13px", color: "var(--ss-text-secondary)" }}>云空间用量</div>
|
||||||
{storageUsageLoading ? (
|
{storageUsageLoading ? (
|
||||||
|
|||||||
+134
-122
@@ -13,7 +13,13 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
} from "antd"
|
} from "antd"
|
||||||
import { SearchOutlined, DeleteOutlined, UndoOutlined, UploadOutlined, CopyOutlined } from "@ant-design/icons"
|
import {
|
||||||
|
SearchOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
UndoOutlined,
|
||||||
|
UploadOutlined,
|
||||||
|
CopyOutlined,
|
||||||
|
} from "@ant-design/icons"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import { match, pinyin } from "pinyin-pro"
|
import { match, pinyin } from "pinyin-pro"
|
||||||
import { getAvatarFromExtraJson, setAvatarInExtraJson } from "../utils/studentAvatar"
|
import { getAvatarFromExtraJson, setAvatarInExtraJson } from "../utils/studentAvatar"
|
||||||
@@ -651,111 +657,114 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
setOperationVisible(true)
|
setOperationVisible(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const playOperationMorph = useCallback((attempt = 0) => {
|
const playOperationMorph = useCallback(
|
||||||
if (isPortraitMode || !operationOriginRect) return false
|
(attempt = 0) => {
|
||||||
const modalEl = document.querySelector(`.${operationModalClass}`) as HTMLElement | null
|
if (isPortraitMode || !operationOriginRect) return false
|
||||||
if (!modalEl) {
|
const modalEl = document.querySelector(`.${operationModalClass}`) as HTMLElement | null
|
||||||
const byClassCount = document.querySelectorAll(`.${operationModalClass}`).length
|
if (!modalEl) {
|
||||||
const byRootCount = document.querySelectorAll(`.${operationModalRootClass}`).length
|
const byClassCount = document.querySelectorAll(`.${operationModalClass}`).length
|
||||||
const modalCount = document.querySelectorAll(".ant-modal").length
|
const byRootCount = document.querySelectorAll(`.${operationModalRootClass}`).length
|
||||||
const rootExists = Boolean(document.querySelector(`.${operationModalRootClass}`))
|
const modalCount = document.querySelectorAll(".ant-modal").length
|
||||||
logHome("operation:morph:modal-miss", {
|
const rootExists = Boolean(document.querySelector(`.${operationModalRootClass}`))
|
||||||
attempt,
|
logHome("operation:morph:modal-miss", {
|
||||||
rootExists,
|
attempt,
|
||||||
byClassCount,
|
rootExists,
|
||||||
byRootCount,
|
byClassCount,
|
||||||
modalCount,
|
byRootCount,
|
||||||
})
|
modalCount,
|
||||||
return false
|
})
|
||||||
}
|
return false
|
||||||
|
|
||||||
// Clear any leftover transform from previous close animation before measuring.
|
|
||||||
operationMorphAnimationRef.current?.cancel()
|
|
||||||
for (const animation of modalEl.getAnimations()) {
|
|
||||||
animation.cancel()
|
|
||||||
}
|
|
||||||
modalEl.style.transform = ""
|
|
||||||
modalEl.style.opacity = ""
|
|
||||||
modalEl.style.visibility = ""
|
|
||||||
const maskEl = document.querySelector(`.${operationModalRootClass} .ant-modal-mask`) as
|
|
||||||
| HTMLElement
|
|
||||||
| null
|
|
||||||
if (maskEl) {
|
|
||||||
operationMaskAnimationRef.current?.cancel()
|
|
||||||
maskEl.style.opacity = ""
|
|
||||||
maskEl.style.visibility = ""
|
|
||||||
operationMaskAnimationRef.current = maskEl.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
||||||
duration: 220,
|
|
||||||
easing: "cubic-bezier(0.2, 0, 0, 1)",
|
|
||||||
fill: "both",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const modalRect = modalEl.getBoundingClientRect()
|
|
||||||
if (modalRect.width <= 0 || modalRect.height <= 0) {
|
|
||||||
logHome("operation:morph:modal-rect-invalid", {
|
|
||||||
attempt,
|
|
||||||
width: modalRect.width,
|
|
||||||
height: modalRect.height,
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const fromX = operationOriginRect.left - modalRect.left
|
|
||||||
const fromY = operationOriginRect.top - modalRect.top
|
|
||||||
const scaleX = operationOriginRect.width / modalRect.width
|
|
||||||
const scaleY = operationOriginRect.height / modalRect.height
|
|
||||||
|
|
||||||
logHome("operation:morph:computed", {
|
|
||||||
modalRect: {
|
|
||||||
left: modalRect.left,
|
|
||||||
top: modalRect.top,
|
|
||||||
width: modalRect.width,
|
|
||||||
height: modalRect.height,
|
|
||||||
},
|
|
||||||
fromX,
|
|
||||||
fromY,
|
|
||||||
scaleX,
|
|
||||||
scaleY,
|
|
||||||
expectedStartRect: {
|
|
||||||
left: modalRect.left + fromX,
|
|
||||||
top: modalRect.top + fromY,
|
|
||||||
width: modalRect.width * scaleX,
|
|
||||||
height: modalRect.height * scaleY,
|
|
||||||
},
|
|
||||||
animateSupported: typeof modalEl.animate === "function",
|
|
||||||
})
|
|
||||||
|
|
||||||
modalEl.style.transformOrigin = "top left"
|
|
||||||
modalEl.style.willChange = "transform, opacity"
|
|
||||||
operationMorphAnimationRef.current = modalEl.animate(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
transform: `translate3d(${fromX}px, ${fromY}px, 0) scale(${scaleX}, ${scaleY})`,
|
|
||||||
opacity: 0.86,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
transform: "translate3d(0, 0, 0) scale(1, 1)",
|
|
||||||
opacity: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
{
|
|
||||||
duration: 480,
|
|
||||||
easing: "cubic-bezier(0.16, 1, 0.3, 1)",
|
|
||||||
fill: "both",
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
logHome("operation:morph:animation-start", {
|
// Clear any leftover transform from previous close animation before measuring.
|
||||||
attempt,
|
operationMorphAnimationRef.current?.cancel()
|
||||||
currentTime: operationMorphAnimationRef.current.currentTime,
|
for (const animation of modalEl.getAnimations()) {
|
||||||
playState: operationMorphAnimationRef.current.playState,
|
animation.cancel()
|
||||||
})
|
}
|
||||||
operationMorphAnimationRef.current.onfinish = () => {
|
modalEl.style.transform = ""
|
||||||
logHome("operation:morph:animation-finish")
|
modalEl.style.opacity = ""
|
||||||
}
|
modalEl.style.visibility = ""
|
||||||
operationMorphAnimationRef.current.oncancel = () => {
|
const maskEl = document.querySelector(
|
||||||
logHome("operation:morph:animation-cancel")
|
`.${operationModalRootClass} .ant-modal-mask`
|
||||||
}
|
) as HTMLElement | null
|
||||||
return true
|
if (maskEl) {
|
||||||
}, [isPortraitMode, operationOriginRect, operationModalClass, operationModalRootClass])
|
operationMaskAnimationRef.current?.cancel()
|
||||||
|
maskEl.style.opacity = ""
|
||||||
|
maskEl.style.visibility = ""
|
||||||
|
operationMaskAnimationRef.current = maskEl.animate([{ opacity: 0 }, { opacity: 1 }], {
|
||||||
|
duration: 220,
|
||||||
|
easing: "cubic-bezier(0.2, 0, 0, 1)",
|
||||||
|
fill: "both",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const modalRect = modalEl.getBoundingClientRect()
|
||||||
|
if (modalRect.width <= 0 || modalRect.height <= 0) {
|
||||||
|
logHome("operation:morph:modal-rect-invalid", {
|
||||||
|
attempt,
|
||||||
|
width: modalRect.width,
|
||||||
|
height: modalRect.height,
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const fromX = operationOriginRect.left - modalRect.left
|
||||||
|
const fromY = operationOriginRect.top - modalRect.top
|
||||||
|
const scaleX = operationOriginRect.width / modalRect.width
|
||||||
|
const scaleY = operationOriginRect.height / modalRect.height
|
||||||
|
|
||||||
|
logHome("operation:morph:computed", {
|
||||||
|
modalRect: {
|
||||||
|
left: modalRect.left,
|
||||||
|
top: modalRect.top,
|
||||||
|
width: modalRect.width,
|
||||||
|
height: modalRect.height,
|
||||||
|
},
|
||||||
|
fromX,
|
||||||
|
fromY,
|
||||||
|
scaleX,
|
||||||
|
scaleY,
|
||||||
|
expectedStartRect: {
|
||||||
|
left: modalRect.left + fromX,
|
||||||
|
top: modalRect.top + fromY,
|
||||||
|
width: modalRect.width * scaleX,
|
||||||
|
height: modalRect.height * scaleY,
|
||||||
|
},
|
||||||
|
animateSupported: typeof modalEl.animate === "function",
|
||||||
|
})
|
||||||
|
|
||||||
|
modalEl.style.transformOrigin = "top left"
|
||||||
|
modalEl.style.willChange = "transform, opacity"
|
||||||
|
operationMorphAnimationRef.current = modalEl.animate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
transform: `translate3d(${fromX}px, ${fromY}px, 0) scale(${scaleX}, ${scaleY})`,
|
||||||
|
opacity: 0.86,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
transform: "translate3d(0, 0, 0) scale(1, 1)",
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
duration: 480,
|
||||||
|
easing: "cubic-bezier(0.16, 1, 0.3, 1)",
|
||||||
|
fill: "both",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
logHome("operation:morph:animation-start", {
|
||||||
|
attempt,
|
||||||
|
currentTime: operationMorphAnimationRef.current.currentTime,
|
||||||
|
playState: operationMorphAnimationRef.current.playState,
|
||||||
|
})
|
||||||
|
operationMorphAnimationRef.current.onfinish = () => {
|
||||||
|
logHome("operation:morph:animation-finish")
|
||||||
|
}
|
||||||
|
operationMorphAnimationRef.current.oncancel = () => {
|
||||||
|
logHome("operation:morph:animation-cancel")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
[isPortraitMode, operationOriginRect, operationModalClass, operationModalRootClass]
|
||||||
|
)
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (isPortraitMode || !operationVisible) return
|
if (isPortraitMode || !operationVisible) return
|
||||||
@@ -787,23 +796,26 @@ export const Home: React.FC<HomeProps> = ({
|
|||||||
}
|
}
|
||||||
}, [isPortraitMode, operationVisible, operationOriginRect, playOperationMorph])
|
}, [isPortraitMode, operationVisible, operationOriginRect, playOperationMorph])
|
||||||
|
|
||||||
const finishCloseOperationModal = useCallback((skipCancelMorph = false, skipCancelMask = false) => {
|
const finishCloseOperationModal = useCallback(
|
||||||
if (!skipCancelMorph) {
|
(skipCancelMorph = false, skipCancelMask = false) => {
|
||||||
operationMorphAnimationRef.current?.cancel()
|
if (!skipCancelMorph) {
|
||||||
}
|
operationMorphAnimationRef.current?.cancel()
|
||||||
operationMorphAnimationRef.current = null
|
}
|
||||||
if (!skipCancelMask) {
|
operationMorphAnimationRef.current = null
|
||||||
operationMaskAnimationRef.current?.cancel()
|
if (!skipCancelMask) {
|
||||||
}
|
operationMaskAnimationRef.current?.cancel()
|
||||||
operationMaskAnimationRef.current = null
|
}
|
||||||
if (operationMorphRafRef.current !== null) {
|
operationMaskAnimationRef.current = null
|
||||||
window.cancelAnimationFrame(operationMorphRafRef.current)
|
if (operationMorphRafRef.current !== null) {
|
||||||
operationMorphRafRef.current = null
|
window.cancelAnimationFrame(operationMorphRafRef.current)
|
||||||
}
|
operationMorphRafRef.current = null
|
||||||
operationClosingRef.current = false
|
}
|
||||||
setOperationVisible(false)
|
operationClosingRef.current = false
|
||||||
setOperationOriginRect(null)
|
setOperationVisible(false)
|
||||||
}, [])
|
setOperationOriginRect(null)
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
const closeOperationModal = useCallback(() => {
|
const closeOperationModal = useCallback(() => {
|
||||||
logHome("operation:morph:close", {
|
logHome("operation:morph:close", {
|
||||||
|
|||||||
@@ -120,7 +120,9 @@ export const RewardExchange: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const frame = window.requestAnimationFrame(() => {
|
const frame = window.requestAnimationFrame(() => {
|
||||||
const modalEl = document.querySelector(".ss-reward-morph-modal.ant-modal") as HTMLElement | null
|
const modalEl = document.querySelector(
|
||||||
|
".ss-reward-morph-modal.ant-modal"
|
||||||
|
) as HTMLElement | null
|
||||||
if (!modalEl) {
|
if (!modalEl) {
|
||||||
setModalMorphStage("idle")
|
setModalMorphStage("idle")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -416,15 +416,13 @@ export const Settings: React.FC<{
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleOAuthUserUpdated = (event: Event) => {
|
const handleOAuthUserUpdated = (event: Event) => {
|
||||||
const customEvent = event as CustomEvent<{
|
const customEvent = event as CustomEvent<{
|
||||||
user?:
|
user?: {
|
||||||
| {
|
user_id?: string
|
||||||
user_id?: string
|
email?: string
|
||||||
email?: string
|
name?: string
|
||||||
name?: string
|
github_username?: string
|
||||||
github_username?: string
|
permission?: number
|
||||||
permission?: number
|
} | null
|
||||||
}
|
|
||||||
| null
|
|
||||||
}>
|
}>
|
||||||
const user = customEvent?.detail?.user
|
const user = customEvent?.detail?.user
|
||||||
if (user?.user_id && user.email && user.name && typeof user.permission === "number") {
|
if (user?.user_id && user.email && user.name && typeof user.permission === "number") {
|
||||||
@@ -442,10 +440,7 @@ export const Settings: React.FC<{
|
|||||||
|
|
||||||
window.addEventListener("ss:oauth-user-updated", handleOAuthUserUpdated as EventListener)
|
window.addEventListener("ss:oauth-user-updated", handleOAuthUserUpdated as EventListener)
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener(
|
window.removeEventListener("ss:oauth-user-updated", handleOAuthUserUpdated as EventListener)
|
||||||
"ss:oauth-user-updated",
|
|
||||||
handleOAuthUserUpdated as EventListener
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user