gitlink_help_center/src/components/FontSizeController.js

415 lines
12 KiB
JavaScript

import React, { useState, useEffect } from 'react';
const FontSizeController = () => {
const [fontSize, setFontSize] = useState('medium');
const [mounted, setMounted] = useState(false);
const [isVisible, setIsVisible] = useState(false);
// 字体大小配置 - 增加更多选项
const fontSizes = {
extraSmall: {
name: '极小',
icon: '🔍',
scale: 0.75, // 12px 基于 16px
description: '超密集阅读'
},
small: {
name: '小号',
icon: '🔤',
scale: 0.875, // 14px 基于 16px
description: '密集阅读'
},
medium: {
name: '标准',
icon: '📝',
scale: 1, // 16px 标准
description: '推荐大小'
},
large: {
name: '大号',
icon: '📖',
scale: 1.125, // 18px 基于 16px
description: '舒适阅读'
},
extraLarge: {
name: '特大',
icon: '📚',
scale: 1.25, // 20px 基于 16px
description: '长时间阅读'
},
huge: {
name: '巨大',
icon: '🔍',
scale: 1.375, // 22px 基于 16px
description: '视力辅助'
}
};
useEffect(() => {
setMounted(true);
// 从localStorage读取保存的字体大小设置
const savedFontSize = localStorage.getItem('doc-font-size') || 'medium';
const savedVisibility = localStorage.getItem('font-controller-visible') === 'true';
setFontSize(savedFontSize);
setIsVisible(savedVisibility);
applyFontSize(savedFontSize);
}, []);
// 应用字体大小到文档
const applyFontSize = (size) => {
const scale = fontSizes[size].scale;
// 创建或更新CSS变量
const root = document.documentElement;
root.style.setProperty('--doc-font-scale', scale);
// 直接应用到文档内容区域
const contentSelectors = [
'article',
'.markdown',
'.theme-doc-markdown',
'[class*="docItemContainer"]',
'[class*="docItemCol"]'
];
contentSelectors.forEach(selector => {
const elements = document.querySelectorAll(selector);
elements.forEach(element => {
element.style.fontSize = `${scale}rem`;
});
});
// 调整特定元素
const specificElements = {
'h1': `${scale * 2.5}rem`,
'h2': `${scale * 2}rem`,
'h3': `${scale * 1.75}rem`,
'h4': `${scale * 1.5}rem`,
'h5': `${scale * 1.25}rem`,
'h6': `${scale * 1.125}rem`,
'p, li, td, th, blockquote': `${scale}rem`,
'code': `${scale * 0.875}rem`,
'.table-of-contents': `${scale * 0.875}rem`
};
Object.entries(specificElements).forEach(([selectors, size]) => {
const elements = document.querySelectorAll(selectors);
elements.forEach(element => {
// 只调整文档内容区域的元素,避免影响导航等
const isInContent = element.closest('article, .markdown, .theme-doc-markdown');
if (isInContent) {
element.style.fontSize = size;
}
});
});
};
// 切换字体大小
const changeFontSize = (size) => {
setFontSize(size);
localStorage.setItem('doc-font-size', size);
applyFontSize(size);
showNotification(`✅ 字体大小已切换为:${fontSizes[size].name}`, 'success');
};
// 切换显示/隐藏
const toggleVisibility = () => {
const newVisibility = !isVisible;
setIsVisible(newVisibility);
localStorage.setItem('font-controller-visible', newVisibility.toString());
showNotification(newVisibility ? '📝 字体调节器已显示' : '👁️ 字体调节器已隐藏', 'info');
};
// 显示通知
const showNotification = (message, type = 'info') => {
try {
const notification = document.createElement('div');
notification.textContent = message;
const bgColors = {
success: '#25c2a0',
info: '#3498db',
warning: '#f39c12'
};
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${bgColors[type] || bgColors.info};
color: white;
padding: 12px 20px;
border-radius: 6px;
font-size: 14px;
z-index: 10000;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
animation: slideIn 0.3s ease;
max-width: 300px;
word-wrap: break-word;
`;
// 添加动画样式
const style = document.createElement('style');
style.textContent = `
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
`;
if (!document.head.querySelector('[data-font-notification-style]')) {
style.setAttribute('data-font-notification-style', 'true');
document.head.appendChild(style);
}
document.body.appendChild(notification);
setTimeout(() => {
if (notification.parentNode) {
notification.remove();
}
}, 3000);
} catch (error) {
console.error('显示通知失败:', error);
}
};
// 如果组件还没挂载,不渲染任何内容
if (!mounted) {
return null;
}
const containerStyle = {
position: 'fixed',
top: '50%',
right: '20px', // 移到右侧
transform: 'translateY(-50%)',
zIndex: 1001,
fontFamily: 'system-ui, -apple-system, sans-serif'
};
const toggleButtonStyle = {
position: 'fixed',
top: '50%',
right: isVisible ? '140px' : '20px', // 根据显示状态调整位置
transform: 'translateY(-50%)',
zIndex: 1002,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '40px',
height: '40px',
backgroundColor: '#3b82f6',
color: 'white',
border: 'none',
borderRadius: '50%',
cursor: 'pointer',
fontSize: '16px',
boxShadow: '0 4px 12px rgba(59, 130, 246, 0.3)',
transition: 'all 0.3s ease',
fontFamily: 'system-ui, -apple-system, sans-serif'
};
const buttonStyle = {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '6px',
padding: '10px',
backgroundColor: 'white',
border: '2px solid #e5e7eb',
borderRadius: '10px',
cursor: 'pointer',
fontSize: '11px',
fontWeight: '600',
color: '#374151',
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
transition: 'all 0.2s ease',
minWidth: '50px',
textAlign: 'center'
};
const activeButtonStyle = {
...buttonStyle,
backgroundColor: '#3b82f6',
borderColor: '#3b82f6',
color: 'white',
transform: 'translateY(-2px)',
boxShadow: '0 6px 16px rgba(59, 130, 246, 0.3)'
};
return (
<>
{/* 切换显示/隐藏按钮 */}
<button
onClick={toggleVisibility}
style={toggleButtonStyle}
onMouseEnter={(e) => {
e.target.style.backgroundColor = '#2563eb';
e.target.style.transform = 'translateY(-50%) scale(1.1)';
}}
onMouseLeave={(e) => {
e.target.style.backgroundColor = '#3b82f6';
e.target.style.transform = 'translateY(-50%) scale(1)';
}}
title={isVisible ? '隐藏字体调节器' : '显示字体调节器'}
>
{isVisible ? '✕' : 'Aa'}
</button>
{/* 字体大小控制面板 */}
{isVisible && (
<div style={containerStyle}>
<div style={{
display: 'flex',
flexDirection: 'column',
gap: '6px',
backgroundColor: 'white',
padding: '12px',
borderRadius: '16px',
boxShadow: '0 8px 24px rgba(0,0,0,0.15)',
border: '1px solid #e5e7eb',
animation: 'slideInFromRight 0.3s ease'
}}>
{/* 标题 */}
<div style={{
fontSize: '11px',
fontWeight: '700',
color: '#6b7280',
textAlign: 'center',
marginBottom: '4px',
letterSpacing: '0.5px'
}}>
字体大小
</div>
{/* 当前字体大小显示 */}
<div style={{
fontSize: '10px',
fontWeight: '600',
color: '#3b82f6',
textAlign: 'center',
marginBottom: '8px',
padding: '4px 8px',
backgroundColor: '#eff6ff',
borderRadius: '6px'
}}>
当前: {fontSizes[fontSize].name} ({Math.round(fontSizes[fontSize].scale * 16)}px)
</div>
{/* 字体大小选项 */}
<div style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: '6px'
}}>
{Object.entries(fontSizes).map(([size, config]) => (
<button
key={size}
onClick={() => changeFontSize(size)}
style={fontSize === size ? activeButtonStyle : buttonStyle}
onMouseEnter={(e) => {
if (fontSize !== size) {
e.target.style.backgroundColor = '#f3f4f6';
e.target.style.borderColor = '#d1d5db';
e.target.style.transform = 'translateY(-1px)';
}
}}
onMouseLeave={(e) => {
if (fontSize !== size) {
e.target.style.backgroundColor = 'white';
e.target.style.borderColor = '#e5e7eb';
e.target.style.transform = 'translateY(0)';
}
}}
title={`${config.name} (${Math.round(config.scale * 16)}px) - ${config.description}`}
>
<span style={{ fontSize: '14px' }}>{config.icon}</span>
<span style={{ fontSize: '9px', fontWeight: '600' }}>
{config.name}
</span>
</button>
))}
</div>
{/* 快捷操作按钮 */}
<div style={{
display: 'flex',
gap: '6px',
marginTop: '8px'
}}>
<button
onClick={() => changeFontSize('medium')}
style={{
...buttonStyle,
backgroundColor: fontSize === 'medium' ? '#6b7280' : '#f9fafb',
borderColor: fontSize === 'medium' ? '#6b7280' : '#e5e7eb',
color: fontSize === 'medium' ? 'white' : '#6b7280',
fontSize: '9px',
padding: '6px 10px',
minWidth: 'auto',
flex: 1
}}
onMouseEnter={(e) => {
if (fontSize !== 'medium') {
e.target.style.backgroundColor = '#f3f4f6';
e.target.style.borderColor = '#d1d5db';
}
}}
onMouseLeave={(e) => {
if (fontSize !== 'medium') {
e.target.style.backgroundColor = '#f9fafb';
e.target.style.borderColor = '#e5e7eb';
}
}}
title="重置为标准大小"
>
重置
</button>
<button
onClick={toggleVisibility}
style={{
...buttonStyle,
backgroundColor: '#ef4444',
borderColor: '#ef4444',
color: 'white',
fontSize: '9px',
padding: '6px 10px',
minWidth: 'auto',
flex: 1
}}
onMouseEnter={(e) => {
e.target.style.backgroundColor = '#dc2626';
e.target.style.borderColor = '#dc2626';
}}
onMouseLeave={(e) => {
e.target.style.backgroundColor = '#ef4444';
e.target.style.borderColor = '#ef4444';
}}
title="隐藏字体调节器"
>
隐藏
</button>
</div>
</div>
</div>
)}
{/* 添加动画样式 */}
<style>{`
@keyframes slideInFromRight {
from {
transform: translateX(100%) translateY(-50%);
opacity: 0;
}
to {
transform: translateX(0) translateY(-50%);
opacity: 1;
}
}
`}</style>
</>
);
};
export default FontSizeController;