improving share mechanism
This commit is contained in:
@ -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,
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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" />
|
||||
</button>
|
||||
<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>
|
||||
|
||||
@ -63,6 +63,7 @@ function shareURL() {
|
||||
renderMode: settings.renderMode,
|
||||
valueMode: settings.valueMode,
|
||||
uiOpacity: settings.uiOpacity,
|
||||
hueShift: settings.hueShift,
|
||||
};
|
||||
|
||||
const encoded = btoa(JSON.stringify(shareData));
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user