improving share mechanism

This commit is contained in:
2025-07-08 13:51:58 +02:00
parent fb2d5c1b4c
commit e0e860f9c9
6 changed files with 110 additions and 3 deletions

View File

@ -18,6 +18,7 @@ export interface SavedShader {
renderMode?: string;
valueMode?: ValueMode;
uiOpacity?: number;
hueShift?: number;
}
export class Storage {
@ -46,6 +47,7 @@ export class Storage {
renderMode: settings.renderMode,
valueMode: settings.valueMode,
uiOpacity: settings.uiOpacity,
hueShift: settings.hueShift,
}),
};

View File

@ -36,6 +36,7 @@ export function ShaderLibrary() {
renderMode: settings.renderMode,
valueMode: settings.valueMode,
uiOpacity: settings.uiOpacity,
hueShift: settings.hueShift,
};
saveShader(name, code, currentSettings);
@ -62,6 +63,8 @@ export function ShaderLibrary() {
if (shaderData.valueMode) newSettings.valueMode = shaderData.valueMode;
if (shaderData.uiOpacity !== undefined)
newSettings.uiOpacity = shaderData.uiOpacity;
if (shaderData.hueShift !== undefined)
newSettings.hueShift = shaderData.hueShift;
if (Object.keys(newSettings).length > 0) {
updateAppSettings(newSettings);

View File

@ -1,4 +1,5 @@
import { useStore } from '@nanostores/react';
import { useState, useEffect } from 'react';
import { $appSettings, updateAppSettings } from '../stores/appSettings';
import { VALUE_MODES, ValueMode } from '../utils/constants';
import {
@ -46,6 +47,7 @@ export function TopBar() {
const shader = useStore($shader);
const input = useStore($input);
const { setupAudio, disableAudio } = useAudio();
const [shareStatus, setShareStatus] = useState<'idle' | 'copied' | 'failed'>('idle');
const handleFullscreen = () => {
if (!document.fullscreenElement) {
@ -68,6 +70,7 @@ export function TopBar() {
renderMode: settings.renderMode,
valueMode: settings.valueMode,
uiOpacity: settings.uiOpacity,
hueShift: settings.hueShift,
};
try {
@ -81,9 +84,13 @@ export function TopBar() {
.writeText(url)
.then(() => {
console.log('URL copied to clipboard');
setShareStatus('copied');
setTimeout(() => setShareStatus('idle'), 2000);
})
.catch(() => {
console.log('Copy failed');
setShareStatus('failed');
setTimeout(() => setShareStatus('idle'), 2000);
});
} catch (error) {
console.error('Failed to create share URL:', error);
@ -283,9 +290,87 @@ export function TopBar() {
name={input.audioEnabled ? 'microphone' : 'microphone-off'}
/>
</button>
<button id="share-btn" onClick={handleShare}>
<LucideIcon name="share" />
<div style={{ position: 'relative', display: 'inline-block' }}>
<button
id="share-btn"
onClick={handleShare}
style={{
background: shareStatus === 'copied' ? '#4CAF50' : shareStatus === 'failed' ? '#f44336' : undefined,
color: shareStatus !== 'idle' ? '#fff' : undefined,
transition: 'all 0.3s ease'
}}
>
<LucideIcon name={shareStatus === 'copied' ? 'check' : 'share'} />
</button>
{shareStatus === 'copied' && (
<div
style={{
position: 'absolute',
top: '100%',
left: '50%',
transform: 'translateX(-50%)',
backgroundColor: '#333',
color: '#fff',
padding: '8px 12px',
borderRadius: '4px',
fontSize: '12px',
whiteSpace: 'nowrap',
zIndex: 1000,
marginTop: '5px',
animation: 'fadeIn 0.3s ease'
}}
>
Link copied to clipboard!
<div
style={{
position: 'absolute',
top: '-5px',
left: '50%',
transform: 'translateX(-50%)',
width: '0',
height: '0',
borderLeft: '5px solid transparent',
borderRight: '5px solid transparent',
borderBottom: '5px solid #333'
}}
/>
</div>
)}
{shareStatus === 'failed' && (
<div
style={{
position: 'absolute',
top: '100%',
left: '50%',
transform: 'translateX(-50%)',
backgroundColor: '#f44336',
color: '#fff',
padding: '8px 12px',
borderRadius: '4px',
fontSize: '12px',
whiteSpace: 'nowrap',
zIndex: 1000,
marginTop: '5px',
animation: 'fadeIn 0.3s ease'
}}
>
Failed to copy link
<div
style={{
position: 'absolute',
top: '-5px',
left: '50%',
transform: 'translateX(-50%)',
width: '0',
height: '0',
borderLeft: '5px solid transparent',
borderRight: '5px solid transparent',
borderBottom: '5px solid #f44336'
}}
/>
</div>
)}
</div>
<button id="export-png-btn" onClick={handleExportPNG}>
<LucideIcon name="export" />
</button>

View File

@ -63,6 +63,7 @@ function shareURL() {
renderMode: settings.renderMode,
valueMode: settings.valueMode,
uiOpacity: settings.uiOpacity,
hueShift: settings.hueShift,
};
const encoded = btoa(JSON.stringify(shareData));

View File

@ -36,6 +36,10 @@ function loadFromURL() {
shareData.uiOpacity !== undefined
? shareData.uiOpacity
: savedSettings.uiOpacity,
hueShift:
shareData.hueShift !== undefined
? shareData.hueShift
: savedSettings.hueShift,
});
console.log('Settings updated from URL');

View File

@ -852,3 +852,15 @@ button [data-lucide] {
grid-template-columns: repeat(3, 1fr);
}
}
/* Share button tooltip animation */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateX(-50%) translateY(-10px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}