@jjlmoya/utils-social 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +60 -0
- package/src/category/i18n/en.ts +23 -0
- package/src/category/i18n/es.ts +23 -0
- package/src/category/i18n/fr.ts +23 -0
- package/src/category/index.ts +13 -0
- package/src/category/seo.astro +15 -0
- package/src/components/PreviewNavSidebar.astro +116 -0
- package/src/components/PreviewToolbar.astro +143 -0
- package/src/data.ts +11 -0
- package/src/env.d.ts +5 -0
- package/src/index.ts +27 -0
- package/src/layouts/PreviewLayout.astro +117 -0
- package/src/pages/[locale]/[slug].astro +146 -0
- package/src/pages/[locale].astro +251 -0
- package/src/pages/index.astro +4 -0
- package/src/tests/faq_count.test.ts +19 -0
- package/src/tests/locale_completeness.test.ts +42 -0
- package/src/tests/mocks/astro_mock.js +2 -0
- package/src/tests/no_h1_in_components.test.ts +48 -0
- package/src/tests/seo_length.test.ts +22 -0
- package/src/tests/tool_validation.test.ts +17 -0
- package/src/tool/redditFormatter/bibliography.astro +14 -0
- package/src/tool/redditFormatter/component.astro +246 -0
- package/src/tool/redditFormatter/i18n/en.ts +193 -0
- package/src/tool/redditFormatter/i18n/es.ts +193 -0
- package/src/tool/redditFormatter/i18n/fr.ts +193 -0
- package/src/tool/redditFormatter/index.ts +34 -0
- package/src/tool/redditFormatter/logic.ts +24 -0
- package/src/tool/redditFormatter/seo.astro +14 -0
- package/src/tool/redditFormatter/ui.ts +13 -0
- package/src/tool/safeZones/bibliography.astro +14 -0
- package/src/tool/safeZones/component.astro +857 -0
- package/src/tool/safeZones/i18n/en.ts +244 -0
- package/src/tool/safeZones/i18n/es.ts +244 -0
- package/src/tool/safeZones/i18n/fr.ts +244 -0
- package/src/tool/safeZones/index.ts +34 -0
- package/src/tool/safeZones/logic.ts +137 -0
- package/src/tool/safeZones/seo.astro +14 -0
- package/src/tool/safeZones/ui.ts +34 -0
- package/src/tool/socialImageResizer/bibliography.astro +14 -0
- package/src/tool/socialImageResizer/component.astro +498 -0
- package/src/tool/socialImageResizer/i18n/en.ts +211 -0
- package/src/tool/socialImageResizer/i18n/es.ts +211 -0
- package/src/tool/socialImageResizer/i18n/fr.ts +211 -0
- package/src/tool/socialImageResizer/index.ts +34 -0
- package/src/tool/socialImageResizer/logic.ts +133 -0
- package/src/tool/socialImageResizer/seo.astro +14 -0
- package/src/tool/socialImageResizer/ui.ts +7 -0
- package/src/tool/socialValueCalculator/bibliography.astro +14 -0
- package/src/tool/socialValueCalculator/component.astro +829 -0
- package/src/tool/socialValueCalculator/i18n/en.ts +310 -0
- package/src/tool/socialValueCalculator/i18n/es.ts +310 -0
- package/src/tool/socialValueCalculator/i18n/fr.ts +310 -0
- package/src/tool/socialValueCalculator/index.ts +34 -0
- package/src/tool/socialValueCalculator/logic.ts +60 -0
- package/src/tool/socialValueCalculator/seo.astro +14 -0
- package/src/tool/socialValueCalculator/ui.ts +31 -0
- package/src/tool/tinderPhotoOptimizer/bibliography.astro +14 -0
- package/src/tool/tinderPhotoOptimizer/component.astro +1514 -0
- package/src/tool/tinderPhotoOptimizer/i18n/en.ts +248 -0
- package/src/tool/tinderPhotoOptimizer/i18n/es.ts +248 -0
- package/src/tool/tinderPhotoOptimizer/i18n/fr.ts +248 -0
- package/src/tool/tinderPhotoOptimizer/index.ts +34 -0
- package/src/tool/tinderPhotoOptimizer/logic.ts +199 -0
- package/src/tool/tinderPhotoOptimizer/seo.astro +14 -0
- package/src/tool/tinderPhotoOptimizer/ui.ts +37 -0
- package/src/tool/youtubeThumbnail/bibliography.astro +14 -0
- package/src/tool/youtubeThumbnail/component.astro +419 -0
- package/src/tool/youtubeThumbnail/i18n/en.ts +207 -0
- package/src/tool/youtubeThumbnail/i18n/es.ts +207 -0
- package/src/tool/youtubeThumbnail/i18n/fr.ts +207 -0
- package/src/tool/youtubeThumbnail/index.ts +34 -0
- package/src/tool/youtubeThumbnail/logic.ts +7 -0
- package/src/tool/youtubeThumbnail/seo.astro +14 -0
- package/src/tool/youtubeThumbnail/ui.ts +13 -0
- package/src/tool/youtubeThumbnailPreviewer/bibliography.astro +14 -0
- package/src/tool/youtubeThumbnailPreviewer/component.astro +791 -0
- package/src/tool/youtubeThumbnailPreviewer/i18n/en.ts +321 -0
- package/src/tool/youtubeThumbnailPreviewer/i18n/es.ts +321 -0
- package/src/tool/youtubeThumbnailPreviewer/i18n/fr.ts +321 -0
- package/src/tool/youtubeThumbnailPreviewer/index.ts +34 -0
- package/src/tool/youtubeThumbnailPreviewer/seo.astro +14 -0
- package/src/tool/youtubeThumbnailPreviewer/ui.ts +19 -0
- package/src/tools.ts +10 -0
- package/src/types.ts +72 -0
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { KnownLocale } from '../../types';
|
|
3
|
+
import type { SocialImageResizerUI } from './ui';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
locale?: KnownLocale;
|
|
7
|
+
ui?: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { ui } = Astro.props;
|
|
11
|
+
const t = (ui ?? {}) as SocialImageResizerUI;
|
|
12
|
+
|
|
13
|
+
const presets = [
|
|
14
|
+
{ id: 'ig-square', name: 'Instagram Square', size: '1080×1080', width: 1080, height: 1080, iconKey: 'instagram' },
|
|
15
|
+
{ id: 'ig-portrait', name: 'Instagram Portrait', size: '1080×1350', width: 1080, height: 1350, iconKey: 'instagram' },
|
|
16
|
+
{ id: 'ig-story', name: 'Stories / TikTok', size: '1080×1920', width: 1080, height: 1920, iconKey: 'phone' },
|
|
17
|
+
{ id: 'yt-thumb', name: 'YouTube Thumb', size: '1280×720', width: 1280, height: 720, iconKey: 'youtube' },
|
|
18
|
+
{ id: 'yt-banner', name: 'YouTube Banner', size: '2560×1440', width: 2560, height: 1440, iconKey: 'youtube' },
|
|
19
|
+
{ id: 'x-post', name: 'X / Twitter Post', size: '1200×675', width: 1200, height: 675, iconKey: 'twitter' },
|
|
20
|
+
{ id: 'x-header', name: 'X / Twitter Header', size: '1500×500', width: 1500, height: 500, iconKey: 'header' },
|
|
21
|
+
{ id: 'li-header', name: 'LinkedIn Cover', size: '1584×396', width: 1584, height: 396, iconKey: 'linkedin' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const icons: Record<string, string> = {
|
|
25
|
+
responsive: `<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M4 6h18V4H4c-1.1 0-2 .9-2 2v11H0v3h14v-3H4V6zm19 2h-6c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zm-1 9h-4v-7h4v7z"/></svg>`,
|
|
26
|
+
instagram: `<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M7.8 2h8.4C19.4 2 22 4.6 22 7.8v8.4a5.8 5.8 0 0 1-5.8 5.8H7.8C4.6 22 2 19.4 2 16.2V7.8A5.8 5.8 0 0 1 7.8 2m-.2 2A3.6 3.6 0 0 0 4 7.6v8.8C4 18.39 5.61 20 7.6 20h8.8a3.6 3.6 0 0 0 3.6-3.6V7.6C20 5.61 18.39 4 16.4 4H7.6m9.65 1.5a1.25 1.25 0 0 1 1.25 1.25A1.25 1.25 0 0 1 17.25 8 1.25 1.25 0 0 1 16 6.75a1.25 1.25 0 0 1 1.25-1.25M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3z"/></svg>`,
|
|
27
|
+
phone: `<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M17 1H7C5.9 1 5 1.9 5 3v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-2-2-2zm0 18H7V5h10v14zm-5 2c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"/></svg>`,
|
|
28
|
+
youtube: `<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M10 15l5.19-3L10 9v6m11.56-7.83c.13.47.22 1.1.28 1.9.07.8.1 1.49.1 2.09L22 12c0 2.19-.16 3.8-.44 4.83-.25.9-.83 1.48-1.73 1.73-.47.13-1.33.22-2.65.28-1.3.07-2.49.1-3.59.1L12 19c-4.19 0-6.8-.16-7.83-.44-.9-.25-1.48-.83-1.73-1.73-.13-.47-.22-1.1-.28-1.9-.07-.8-.1-1.49-.1-2.09L2 12c0-2.19.16-3.8.44-4.83.25-.9.83-1.48 1.73-1.73.47-.13 1.33-.22 2.65-.28 1.3-.07 2.49-.1 3.59-.1L12 5c4.19 0 6.8.16 7.83.44.9.25 1.48.83 1.73 1.73z"/></svg>`,
|
|
29
|
+
twitter: `<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.73-8.835L1.254 2.25H8.08l4.263 5.637zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>`,
|
|
30
|
+
header: `<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M2 5v4h20V5H2zm0 6v8h20v-8H2z"/></svg>`,
|
|
31
|
+
linkedin: `<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.79M6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37h2.77z"/></svg>`,
|
|
32
|
+
upload: `<svg viewBox="0 0 24 24" fill="currentColor" width="40" height="40"><path d="M14 13v4h-4v-4H7l5-5 5 5h-3zm5 6H5v2h14v-2zM5 3h14v8h-2V5H7v6H5V3z"/></svg>`,
|
|
33
|
+
zoomOut: `<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 0 0 9.5 3 6.5 6.5 0 0 0 3 9.5 6.5 6.5 0 0 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM7 9h5v1H7V9z"/></svg>`,
|
|
34
|
+
zoomIn: `<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 0 0 9.5 3 6.5 6.5 0 0 0 3 9.5 6.5 6.5 0 0 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM10 9H9v2H7v1h2v2h1v-2h2V11h-2V9z"/></svg>`,
|
|
35
|
+
refresh: `<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>`,
|
|
36
|
+
download: `<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M5 20h14v-2H5m14-9h-4V3H9v6H5l7 7 7-7z"/></svg>`,
|
|
37
|
+
};
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
<div class="sri-container">
|
|
41
|
+
<aside class="sri-sidebar">
|
|
42
|
+
<div class="sri-sidebar-section">
|
|
43
|
+
<h3 class="sri-sidebar-title">
|
|
44
|
+
<span set:html={icons.responsive} />
|
|
45
|
+
{t.sidebarTitle}
|
|
46
|
+
</h3>
|
|
47
|
+
<div class="sri-preset-grid">
|
|
48
|
+
{presets.map((p, index) => (
|
|
49
|
+
<button
|
|
50
|
+
class={`sri-preset-btn${index === 0 ? ' active' : ''}`}
|
|
51
|
+
data-preset={JSON.stringify({ id: p.id, name: p.name, width: p.width, height: p.height, platform: p.iconKey })}
|
|
52
|
+
id={`sri-btn-${p.id}`}
|
|
53
|
+
>
|
|
54
|
+
<div class="sri-preset-icon">
|
|
55
|
+
<span set:html={icons[p.iconKey]} />
|
|
56
|
+
</div>
|
|
57
|
+
<div class="sri-preset-info">
|
|
58
|
+
<span class="sri-preset-name">{p.name}</span>
|
|
59
|
+
<span class="sri-preset-size">{p.size}</span>
|
|
60
|
+
</div>
|
|
61
|
+
</button>
|
|
62
|
+
))}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</aside>
|
|
66
|
+
|
|
67
|
+
<main class="sri-main">
|
|
68
|
+
<div class="sri-upload-zone" id="sri-dropzone">
|
|
69
|
+
<div class="sri-upload-icon">
|
|
70
|
+
<span set:html={icons.upload} />
|
|
71
|
+
</div>
|
|
72
|
+
<div class="sri-upload-text">
|
|
73
|
+
<h2>{t.uploadTitle}</h2>
|
|
74
|
+
<p>{t.uploadSubtitle}</p>
|
|
75
|
+
</div>
|
|
76
|
+
<input type="file" id="sri-file-input" accept="image/*" hidden />
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="sri-editor-view" id="sri-editor-view">
|
|
80
|
+
<div class="sri-canvas-container" id="sri-canvas-container">
|
|
81
|
+
<canvas id="sri-canvas"></canvas>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div class="sri-editor-actions">
|
|
85
|
+
<div class="sri-zoom-control">
|
|
86
|
+
<span set:html={icons.zoomOut} />
|
|
87
|
+
<input type="range" id="sri-zoom-range" min="10" max="300" value="100" />
|
|
88
|
+
<span set:html={icons.zoomIn} />
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div class="sri-btn-group">
|
|
92
|
+
<button class="sri-action-btn" id="sri-reset-btn">
|
|
93
|
+
<span set:html={icons.refresh} />
|
|
94
|
+
{t.btnReset}
|
|
95
|
+
</button>
|
|
96
|
+
<button class="sri-action-btn sri-primary" id="sri-download-btn">
|
|
97
|
+
<span set:html={icons.download} />
|
|
98
|
+
{t.btnDownload}
|
|
99
|
+
</button>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</main>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<script>
|
|
107
|
+
import { SocialResizer } from './logic';
|
|
108
|
+
|
|
109
|
+
let resizer: SocialResizer | null = null;
|
|
110
|
+
let dropzoneEl: HTMLElement | null = null;
|
|
111
|
+
let editorViewEl: HTMLElement | null = null;
|
|
112
|
+
|
|
113
|
+
async function handleFile(file: File) {
|
|
114
|
+
if (!file.type.startsWith('image/') || !resizer || !dropzoneEl) return;
|
|
115
|
+
await resizer.loadImage(file);
|
|
116
|
+
dropzoneEl.style.display = 'none';
|
|
117
|
+
editorViewEl?.classList.add('active');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function setupDropzone(dropzone: HTMLElement, fileInput: HTMLInputElement) {
|
|
121
|
+
dropzone.addEventListener('click', () => fileInput.click());
|
|
122
|
+
fileInput.addEventListener('change', async (e: Event) => {
|
|
123
|
+
const file = (e.target as HTMLInputElement).files?.[0];
|
|
124
|
+
if (file) await handleFile(file);
|
|
125
|
+
});
|
|
126
|
+
dropzone.addEventListener('dragover', (e) => {
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
dropzone.classList.add('sri-hover');
|
|
129
|
+
});
|
|
130
|
+
dropzone.addEventListener('dragleave', () => dropzone.classList.remove('sri-hover'));
|
|
131
|
+
dropzone.addEventListener('drop', async (e: DragEvent) => {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
const file = e.dataTransfer?.files[0];
|
|
134
|
+
if (file) await handleFile(file);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function setupPresets(presetBtns: NodeListOf<Element>, zoomRange: HTMLInputElement | null) {
|
|
139
|
+
presetBtns.forEach((btn) => {
|
|
140
|
+
btn.addEventListener('click', () => {
|
|
141
|
+
const preset = JSON.parse(btn.getAttribute('data-preset')!);
|
|
142
|
+
presetBtns.forEach((b) => b.classList.remove('active'));
|
|
143
|
+
btn.classList.add('active');
|
|
144
|
+
resizer?.setPreset(preset);
|
|
145
|
+
if (zoomRange) zoomRange.value = '100';
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function setupControls(zoomRange: HTMLInputElement | null, resetBtn: HTMLElement | null, downloadBtn: HTMLElement | null) {
|
|
151
|
+
zoomRange?.addEventListener('input', () => {
|
|
152
|
+
resizer?.setScale(parseInt(zoomRange.value) / 100);
|
|
153
|
+
});
|
|
154
|
+
resetBtn?.addEventListener('click', () => {
|
|
155
|
+
const activeBtn = document.querySelector('.sri-preset-btn.active');
|
|
156
|
+
if (activeBtn) {
|
|
157
|
+
resizer?.setPreset(JSON.parse(activeBtn.getAttribute('data-preset')!));
|
|
158
|
+
if (zoomRange) zoomRange.value = '100';
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
downloadBtn?.addEventListener('click', () => resizer?.download());
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function init() {
|
|
165
|
+
const dropzone = document.getElementById('sri-dropzone');
|
|
166
|
+
const fileInput = document.getElementById('sri-file-input') as HTMLInputElement | null;
|
|
167
|
+
if (!dropzone || !fileInput) return;
|
|
168
|
+
dropzoneEl = dropzone;
|
|
169
|
+
editorViewEl = document.getElementById('sri-editor-view');
|
|
170
|
+
const presetBtns = document.querySelectorAll('.sri-preset-btn');
|
|
171
|
+
const zoomRange = document.getElementById('sri-zoom-range') as HTMLInputElement | null;
|
|
172
|
+
resizer = new SocialResizer('sri-canvas');
|
|
173
|
+
resizer.zoomRangeEl = zoomRange;
|
|
174
|
+
setupDropzone(dropzone, fileInput);
|
|
175
|
+
setupPresets(presetBtns, zoomRange);
|
|
176
|
+
setupControls(zoomRange, document.getElementById('sri-reset-btn'), document.getElementById('sri-download-btn'));
|
|
177
|
+
resizer.setPreset(JSON.parse(presetBtns[0].getAttribute('data-preset')!));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
document.addEventListener('astro:page-load', init);
|
|
181
|
+
init();
|
|
182
|
+
</script>
|
|
183
|
+
|
|
184
|
+
<style>
|
|
185
|
+
.sri-container {
|
|
186
|
+
--bg: #fff;
|
|
187
|
+
--bg-sidebar: #f8fafc;
|
|
188
|
+
--bg-main: #fff;
|
|
189
|
+
--bg-upload: #f8fafc;
|
|
190
|
+
--bg-upload-icon: #fff;
|
|
191
|
+
--bg-canvas: #f1f5f9;
|
|
192
|
+
--bg-btn: #fff;
|
|
193
|
+
--bg-btn-hover: #f8fafc;
|
|
194
|
+
--bg-zoom: #fff;
|
|
195
|
+
--bg-preset-icon: #f1f5f9;
|
|
196
|
+
--bg-preset-hover: #f5f3ff;
|
|
197
|
+
--border: #e2e8f0;
|
|
198
|
+
--text: #1e293b;
|
|
199
|
+
--text-sidebar-title: #64748b;
|
|
200
|
+
--text-upload-sub: #64748b;
|
|
201
|
+
--text-zoom: #64748b;
|
|
202
|
+
--text-action: #475569;
|
|
203
|
+
--text-preset-name: #1e293b;
|
|
204
|
+
--text-preset-size: #64748b;
|
|
205
|
+
|
|
206
|
+
width: 100%;
|
|
207
|
+
max-width: 1200px;
|
|
208
|
+
margin: 0 auto;
|
|
209
|
+
background: var(--bg);
|
|
210
|
+
border-radius: 32px;
|
|
211
|
+
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.08);
|
|
212
|
+
display: grid;
|
|
213
|
+
grid-template-columns: 320px 1fr;
|
|
214
|
+
overflow: hidden;
|
|
215
|
+
color: var(--text);
|
|
216
|
+
border: 1px solid var(--border);
|
|
217
|
+
min-height: 700px;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.sri-sidebar {
|
|
221
|
+
background: var(--bg-sidebar);
|
|
222
|
+
border-right: 1px solid var(--border);
|
|
223
|
+
padding: 2rem;
|
|
224
|
+
display: flex;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
gap: 2rem;
|
|
227
|
+
overflow-y: auto;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.sri-sidebar-title {
|
|
231
|
+
font-size: 0.85rem;
|
|
232
|
+
font-weight: 800;
|
|
233
|
+
text-transform: uppercase;
|
|
234
|
+
letter-spacing: 0.1em;
|
|
235
|
+
color: var(--text-sidebar-title);
|
|
236
|
+
margin-bottom: 1.25rem;
|
|
237
|
+
display: flex;
|
|
238
|
+
align-items: center;
|
|
239
|
+
gap: 0.5rem;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.sri-preset-grid {
|
|
243
|
+
display: flex;
|
|
244
|
+
flex-direction: column;
|
|
245
|
+
gap: 0.75rem;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.sri-preset-btn {
|
|
249
|
+
width: 100%;
|
|
250
|
+
padding: 1rem;
|
|
251
|
+
background: var(--bg-btn);
|
|
252
|
+
border: 1px solid var(--border);
|
|
253
|
+
border-radius: 16px;
|
|
254
|
+
display: flex;
|
|
255
|
+
align-items: center;
|
|
256
|
+
gap: 1rem;
|
|
257
|
+
cursor: pointer;
|
|
258
|
+
transition: all 0.2s ease;
|
|
259
|
+
text-align: left;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.sri-preset-btn:hover {
|
|
263
|
+
border-color: #8b5cf6;
|
|
264
|
+
background: var(--bg-preset-hover);
|
|
265
|
+
transform: translateX(4px);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.sri-preset-btn.active {
|
|
269
|
+
background: #8b5cf6;
|
|
270
|
+
border-color: #7c3aed;
|
|
271
|
+
color: #fff;
|
|
272
|
+
box-shadow: 0 10px 20px rgba(139, 92, 246, 0.2);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.sri-preset-icon {
|
|
276
|
+
width: 40px;
|
|
277
|
+
height: 40px;
|
|
278
|
+
background: var(--bg-preset-icon);
|
|
279
|
+
border-radius: 10px;
|
|
280
|
+
display: flex;
|
|
281
|
+
align-items: center;
|
|
282
|
+
justify-content: center;
|
|
283
|
+
color: var(--text-sidebar-title);
|
|
284
|
+
flex-shrink: 0;
|
|
285
|
+
transition: all 0.2s ease;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.sri-preset-btn.active .sri-preset-icon {
|
|
289
|
+
background: rgba(255, 255, 255, 0.2);
|
|
290
|
+
color: #fff;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.sri-preset-info {
|
|
294
|
+
display: flex;
|
|
295
|
+
flex-direction: column;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.sri-preset-name {
|
|
299
|
+
font-size: 0.95rem;
|
|
300
|
+
font-weight: 700;
|
|
301
|
+
color: var(--text-preset-name);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.sri-preset-size {
|
|
305
|
+
font-size: 0.75rem;
|
|
306
|
+
color: var(--text-preset-size);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.sri-main {
|
|
310
|
+
background: var(--bg-main);
|
|
311
|
+
padding: 3rem;
|
|
312
|
+
display: flex;
|
|
313
|
+
flex-direction: column;
|
|
314
|
+
gap: 2rem;
|
|
315
|
+
position: relative;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.sri-upload-zone {
|
|
319
|
+
flex: 1;
|
|
320
|
+
border: 3px dashed var(--border);
|
|
321
|
+
border-radius: 24px;
|
|
322
|
+
display: flex;
|
|
323
|
+
flex-direction: column;
|
|
324
|
+
align-items: center;
|
|
325
|
+
justify-content: center;
|
|
326
|
+
gap: 1.5rem;
|
|
327
|
+
cursor: pointer;
|
|
328
|
+
transition: all 0.3s ease;
|
|
329
|
+
background: var(--bg-upload);
|
|
330
|
+
min-height: 400px;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.sri-upload-zone:hover,
|
|
334
|
+
.sri-upload-zone.sri-hover {
|
|
335
|
+
border-color: #8b5cf6;
|
|
336
|
+
background: var(--bg-preset-hover);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.sri-upload-icon {
|
|
340
|
+
width: 80px;
|
|
341
|
+
height: 80px;
|
|
342
|
+
background: var(--bg-upload-icon);
|
|
343
|
+
border-radius: 50%;
|
|
344
|
+
display: flex;
|
|
345
|
+
align-items: center;
|
|
346
|
+
justify-content: center;
|
|
347
|
+
color: #8b5cf6;
|
|
348
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.sri-upload-text {
|
|
352
|
+
text-align: center;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.sri-upload-text h2 {
|
|
356
|
+
font-size: 1.5rem;
|
|
357
|
+
font-weight: 900;
|
|
358
|
+
margin-bottom: 0.5rem;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.sri-upload-text p {
|
|
362
|
+
color: var(--text-upload-sub);
|
|
363
|
+
font-size: 0.95rem;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.sri-editor-view {
|
|
367
|
+
display: none;
|
|
368
|
+
flex-direction: column;
|
|
369
|
+
gap: 2rem;
|
|
370
|
+
height: 100%;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.sri-editor-view.active {
|
|
374
|
+
display: flex;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.sri-canvas-container {
|
|
378
|
+
flex: 1;
|
|
379
|
+
background: var(--bg-canvas);
|
|
380
|
+
border-radius: 24px;
|
|
381
|
+
overflow: hidden;
|
|
382
|
+
display: flex;
|
|
383
|
+
align-items: center;
|
|
384
|
+
justify-content: center;
|
|
385
|
+
min-height: 400px;
|
|
386
|
+
border: 1px solid var(--border);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.sri-canvas-container canvas {
|
|
390
|
+
max-width: 100%;
|
|
391
|
+
max-height: 100%;
|
|
392
|
+
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.15);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.sri-editor-actions {
|
|
396
|
+
display: flex;
|
|
397
|
+
justify-content: space-between;
|
|
398
|
+
align-items: center;
|
|
399
|
+
padding-top: 1rem;
|
|
400
|
+
border-top: 1px solid var(--border);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.sri-btn-group {
|
|
404
|
+
display: flex;
|
|
405
|
+
gap: 1rem;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.sri-action-btn {
|
|
409
|
+
padding: 0.75rem 1.5rem;
|
|
410
|
+
border-radius: 12px;
|
|
411
|
+
font-weight: 700;
|
|
412
|
+
display: flex;
|
|
413
|
+
align-items: center;
|
|
414
|
+
gap: 0.5rem;
|
|
415
|
+
cursor: pointer;
|
|
416
|
+
transition: all 0.2s ease;
|
|
417
|
+
border: 1px solid var(--border);
|
|
418
|
+
background: var(--bg-btn);
|
|
419
|
+
color: var(--text-action);
|
|
420
|
+
font-size: 0.9rem;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.sri-action-btn:hover {
|
|
424
|
+
background: var(--bg-btn-hover);
|
|
425
|
+
border-color: var(--border);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.sri-action-btn.sri-primary {
|
|
429
|
+
background: #8b5cf6;
|
|
430
|
+
border-color: #7c3aed;
|
|
431
|
+
color: #fff;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.sri-action-btn.sri-primary:hover {
|
|
435
|
+
background: #7c3aed;
|
|
436
|
+
box-shadow: 0 10px 20px rgba(139, 92, 246, 0.2);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.sri-zoom-control {
|
|
440
|
+
display: flex;
|
|
441
|
+
align-items: center;
|
|
442
|
+
gap: 1rem;
|
|
443
|
+
background: var(--bg-zoom);
|
|
444
|
+
padding: 0.5rem 1rem;
|
|
445
|
+
border-radius: 100px;
|
|
446
|
+
border: 1px solid var(--border);
|
|
447
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
|
448
|
+
color: var(--text-zoom);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.sri-zoom-control input[type='range'] {
|
|
452
|
+
width: 150px;
|
|
453
|
+
accent-color: #8b5cf6;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
:global(.theme-dark) .sri-container {
|
|
457
|
+
--bg: #1e1e21;
|
|
458
|
+
--bg-sidebar: #161618;
|
|
459
|
+
--bg-main: #1e1e21;
|
|
460
|
+
--bg-upload: #161618;
|
|
461
|
+
--bg-upload-icon: #1e1e21;
|
|
462
|
+
--bg-canvas: #111113;
|
|
463
|
+
--bg-btn: #1e1e21;
|
|
464
|
+
--bg-btn-hover: #2d2d30;
|
|
465
|
+
--bg-zoom: #1e1e21;
|
|
466
|
+
--bg-preset-icon: #161618;
|
|
467
|
+
--bg-preset-hover: #232326;
|
|
468
|
+
--border: #2d2d30;
|
|
469
|
+
--text: #f1f5f9;
|
|
470
|
+
--text-sidebar-title: #94a3b8;
|
|
471
|
+
--text-upload-sub: #94a3b8;
|
|
472
|
+
--text-zoom: #94a3b8;
|
|
473
|
+
--text-action: #f1f5f9;
|
|
474
|
+
--text-preset-name: #f1f5f9;
|
|
475
|
+
--text-preset-size: #94a3b8;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
@media (max-width: 900px) {
|
|
479
|
+
.sri-container {
|
|
480
|
+
grid-template-columns: 1fr;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.sri-sidebar {
|
|
484
|
+
border-right: none;
|
|
485
|
+
border-bottom: 1px solid var(--border);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.sri-editor-actions {
|
|
489
|
+
flex-direction: column;
|
|
490
|
+
gap: 1rem;
|
|
491
|
+
align-items: stretch;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.sri-btn-group {
|
|
495
|
+
justify-content: center;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
</style>
|