preview clear

This commit is contained in:
cruise 2025-03-19 00:29:16 +08:00
parent 2d1a52324e
commit 04a85d8874
4 changed files with 395 additions and 29 deletions

View file

@ -3,4 +3,13 @@
This image-sharing plugin for Obsidian (https://obsidian.md) allows you to share selected text as beautiful images.
v0.0.2
- 引入markdwn-here样式
- 优化预览样式
- 调整下载按钮位置
v0.0.1
- 初始化插件

101
main.css

File diff suppressed because one or more lines are too long

196
main.ts
View file

@ -59,10 +59,53 @@ class ImageGenerator {
styleSheet.textContent = `
.markdown-here-wrapper {
font-size: 16px;
line-height: 1.8em;
letter-spacing: 0.1em;
line-height: 2.0em; /* 增加行高 */
letter-spacing: 0.12em; /* 增加字间距 */
}
/* 增加段落间距和内边距 */
p {
margin: 1.8em 5px !important;
padding: 0.2em 0;
}
/* 优化列表项间距 */
li {
margin: 12px 0;
line-height: 1.8em;
}
/* 改善标题样式 */
h1, h2, h3, h4, h5, h6 {
margin: 28px 0 18px !important;
padding: 0.6em 1em !important;
line-height: 1.5em;
}
/* 优化引用块样式 */
blockquote, q {
padding: 10px 15px;
margin: 15px 0;
line-height: 1.8em;
}
/* 列表项内容间距 */
ul, ol {
padding-left: 25px;
margin: 15px 5px;
}
/* 确保代码块不会挤压 */
pre {
margin: 15px 0;
padding: 12px;
line-height: 1.5em;
}
/* 添加内容容器的整体间距 */
.markdown-preview-sizer {
padding: 10px 5px;
}
pre, code {
font-size: 14px;
@ -239,22 +282,28 @@ class ImageGenerator {
const minHeight = 200;
const finalHeight = Math.max(actualHeight, minHeight);
// 使用 html2canvas 渲染时使用计算出的高度
// 增加像素密度和图像质量
const renderedCanvas = await html2canvas(tempDiv, {
width: this.currentTemplate.width,
height: finalHeight,
backgroundColor: this.currentTemplate.id === 'dark' ? '#2d3436' : '#e8ecf9',
scale: 2,
scale: 3, // 增加到3提高清晰度
windowWidth: this.currentTemplate.width,
windowHeight: finalHeight,
logging: true,
logging: false, // 减少日志输出
useCORS: true,
imageTimeout: 0, // 防止图像加载超时
allowTaint: true, // 允许跨域图像
onclone: (clonedDoc) => {
const clonedDiv = clonedDoc.querySelector('.markdown-preview-view') as HTMLElement;
if (clonedDiv) {
clonedDiv.style.width = `${this.currentTemplate.width - 40}px`;
clonedDiv.style.height = `${finalHeight}px`;
clonedDiv.style.overflow = 'visible';
// 增加文本渲染清晰度
clonedDiv.style.textRendering = 'optimizeLegibility';
clonedDiv.style['webkitFontSmoothing' as any] = 'antialiased';
clonedDiv.style['mozOsxFontSmoothing' as any] = 'grayscale';
}
}
});
@ -275,9 +324,20 @@ class ImageGenerator {
}
public getDataURL(): string {
return this.canvas.toDataURL('image/png');
// 增加输出质量使用PNG格式以保持最佳质量
return this.canvas.toDataURL('image/png', 1.0);
}
public async downloadAsImage() {
// 获取当前活动文件的名称
const activeFile = this.app.workspace.getActiveFile();
const fileName = activeFile ? activeFile.basename : 'share-image';
const dataURL = this.getDataURL();
const a = document.createElement('a');
a.href = dataURL;
a.download = `${fileName}.png`;
a.click();
}
public async setTemplate(templateId: string) {
const template = SHARE_TEMPLATES.find(t => t.id === templateId);
if (template) {
@ -285,6 +345,11 @@ class ImageGenerator {
await this.updateCanvas();
}
}
// 添加获取当前模板的方法
public getCurrentTemplate(): ShareTemplate {
return this.currentTemplate;
}
}
class TextPreviewModal extends Modal {
@ -302,7 +367,13 @@ class TextPreviewModal extends Modal {
contentEl.empty();
contentEl.addClass('image-share-modal');
// 根据当前模板宽度设置弹出框宽度,加上一些边距
const modalPadding = 48; // 左右各24px的内边距
const initialWidth = this.imageGenerator.getCurrentTemplate().width + modalPadding;
contentEl.style.width = `${initialWidth}px`;
const resizableContainer = contentEl.createDiv({ cls: 'resizable-container' });
const previewContainer = resizableContainer.createDiv({ cls: 'image-preview-container' });
// 创建顶部操作区
@ -314,7 +385,7 @@ class TextPreviewModal extends Modal {
// 创建画布容器
const canvasContainer = previewContainer.createDiv({ cls: 'canvas-container' });
// 创建模板选择器
SHARE_TEMPLATES.forEach(template => {
const templateButton = templateSelector.createEl('button', {
@ -329,32 +400,109 @@ class TextPreviewModal extends Modal {
await this.imageGenerator.setTemplate(template.id);
canvasContainer.empty();
canvasContainer.appendChild(this.imageGenerator.getCanvas());
// 当模板变更时更新弹出框宽度
const modalPadding = 48; // 与初始化时相同的边距
const newWidth = this.imageGenerator.getCurrentTemplate().width + modalPadding;
contentEl.style.width = `${newWidth}px`;
};
if (template.id === 'default') {
templateButton.addClass('active');
}
});
// 添加缩放控制
const zoomControls = previewContainer.createDiv({ cls: 'zoom-controls' });
const zoomOutBtn = zoomControls.createEl('button', {
cls: 'zoom-button zoom-out',
attr: { 'aria-label': '缩小预览' }
});
zoomOutBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>';
const zoomText = zoomControls.createEl('span', {
cls: 'zoom-text',
text: '100%'
});
const zoomInBtn = zoomControls.createEl('button', {
cls: 'zoom-button zoom-in',
attr: { 'aria-label': '放大预览' }
});
zoomInBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>';
// 缩放逻辑
let zoomLevel = 100;
zoomOutBtn.addEventListener('click', () => {
if (zoomLevel > 50) {
zoomLevel -= 10;
updateZoom();
}
});
zoomInBtn.addEventListener('click', () => {
if (zoomLevel < 200) {
zoomLevel += 10;
updateZoom();
}
});
const updateZoom = () => {
const canvas = canvasContainer.querySelector('canvas');
if (canvas) {
canvas.style.width = `${zoomLevel}%`;
zoomText.textContent = `${zoomLevel}%`;
}
};
// 等待初始画布渲染完成
await this.imageGenerator.updateCanvas();
canvasContainer.appendChild(this.imageGenerator.getCanvas());
// 添加下载按钮
const downloadButton = contentEl.createEl('button', {
cls: 'download-button',
attr: {'title': '下载图片'}
// 创建一个容器来包裹所有内容
// const contentContainer = this.contentEl.createDiv({
// cls: 'text-preview-container'
// });
// // 创建预览区域
// const previewContainer = contentContainer.createDiv({
// cls: 'preview-container'
// });
// // 将原有的预览内容放入预viewContainer
// this.imageGenerator.generatePreview(previewContainer);
// // 创建底部按钮容器
const buttonContainer = resizableContainer.createDiv({
cls: 'download-button'
});
// 将下载按钮放入底部容器
const downloadButton = buttonContainer.createEl('button', {
cls: 'elegant-download-button',
attr: { 'aria-label': '下载为图片' }
});
downloadButton.innerHTML = `<svg viewBox="0 0 24 24">
<path fill="currentColor" d="M12 15.5a.74.74 0 0 1-.53-.22l-3-3A.75.75 0 0 1 9.53 11L12 13.44L14.47 11a.75.75 0 0 1 1.06 1.06l-3 3a.74.74 0 0 1-.53.22zm0-7.5a.75.75 0 0 1 .75.75v6a.75.75 0 0 1-1.5 0v-6A.75.75 0 0 1 12 8z"/>
<path fill="currentColor" d="M19.5 20.5h-15a.75.75 0 0 1 0-1.5h15a.75.75 0 0 1 0 1.5z"/>
</svg>`;
downloadButton.onclick = () => {
const link = document.createElement('a');
link.download = 'share-image.png';
link.href = this.imageGenerator.getDataURL();
link.click();
};
// 使用SVG图标代替文本
downloadButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="7 10 12 15 17 10"></polyline>
<line x1="12" y1="15" x2="12" y2="3"></line>
</svg>
`;
downloadButton.addEventListener('click', async () => {
// 添加点击反馈效果
downloadButton.classList.add('clicked');
setTimeout(() => downloadButton.classList.remove('clicked'), 300);
await this.imageGenerator.downloadAsImage();
});
// // 添加样式
this.contentEl.addClass('text-preview-modal');
}
onClose() {
@ -376,13 +524,13 @@ const SHARE_TEMPLATES: ShareTemplate[] = [
{
id: 'default',
name: '默认模板',
width: 800,
width: 400,
render: async () => {}
},
{
id: 'dark',
name: '深色模板',
width: 800,
width: 400,
render: async () => {}
}
];

View file

@ -10,6 +10,9 @@ If your plugin does not need CSS, delete this file.
.image-share-modal {
max-width: none;
max-height: none;
/* 移除固定宽度以便通过JavaScript动态设置 */
/* width: 1000px; */
transition: width 0.3s ease;
}
.image-share-modal .resizable-container {
@ -50,7 +53,7 @@ If your plugin does not need CSS, delete this file.
height: 100%;
display: flex;
flex-direction: column;
padding: 20px 24px;
padding: 5px 5px;
box-sizing: border-box;
gap: 16px;
position: relative;
@ -64,12 +67,14 @@ If your plugin does not need CSS, delete this file.
display: flex;
justify-content: center;
align-items: flex-start;
padding: 16px;
padding: 2px;
background: var(--background-secondary);
border-radius: 8px;
min-height: 200px;
margin-bottom: 60px;
width: 100%;
overflow: auto;
max-height: 70vh;
}
.image-share-modal h2 {
@ -116,6 +121,10 @@ If your plugin does not need CSS, delete this file.
height: auto;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
transform: translateZ(0);
backface-visibility: hidden;
}
.image-share-modal .template-selector {
@ -149,3 +158,108 @@ If your plugin does not need CSS, delete this file.
.image-preview-container .markdown-preview-view {
padding: 24px;
}
.text-preview-modal .text-preview-container {
display: flex;
flex-direction: column;
height: 100%;
}
.text-preview-modal .preview-container {
flex: 1;
overflow-y: auto;
margin-bottom: 16px;
}
.text-preview-modal .button-container {
display: flex;
justify-content: center;
padding: 8px 0;
border-top: 1px solid var(--background-modifier-border);
}
.text-preview-modal .button-container button {
padding: 8px 16px;
}
.elegant-download-button {
position: absolute;
top: 10px;
right: 10px;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.9);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
z-index: 10;
}
.elegant-download-button:hover {
background-color: #f0f0f0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
.elegant-download-button svg {
color: #4285f4; /* 使用谷歌蓝或其他适合你应用的颜色 */
}
.elegant-download-button.clicked {
transform: scale(0.9);
background-color: #e8e8e8;
}
/* 在暗色模式下的样式调整 */
.theme-dark .elegant-download-button {
background-color: rgba(50, 50, 50, 0.9);
}
.theme-dark .elegant-download-button:hover {
background-color: rgba(60, 60, 60, 0.9);
}
.theme-dark .elegant-download-button svg {
color: #8ab4f8; /* 暗色模式下的蓝色 */
}
/* 添加缩放控制样式 */
.image-share-modal .zoom-controls {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin-bottom: 10px;
}
.image-share-modal .zoom-button {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 50%;
border: 1px solid var(--interactive-accent);
background: transparent;
color: var(--interactive-accent);
cursor: pointer;
transition: all 0.2s ease;
}
.image-share-modal .zoom-button:hover {
background: var(--interactive-accent);
color: var(--text-on-accent);
}
.image-share-modal .zoom-text {
font-size: 14px;
font-weight: 500;
color: var(--text-normal);
width: 50px;
text-align: center;
}