Skip to content

Commit

Permalink
Merge pull request #710 from live-codes/copy-image
Browse files Browse the repository at this point in the history
Share/Copy image menu
  • Loading branch information
hatemhosny authored Jan 11, 2025
2 parents 9dd7dba + 010f065 commit b3b1555
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 47 deletions.
97 changes: 60 additions & 37 deletions src/livecodes/UI/code-to-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
copyToClipboard,
debounce,
downloadFile,
isMobile,
loadScript,
loadStylesheet,
} from '../utils';
Expand Down Expand Up @@ -233,23 +232,6 @@ export const createCodeToImageUI = async ({
},
);

eventsManager.addEventListener(
codeToImageContainer.querySelector<HTMLElement>('#code-to-img-copy-link'),
'click',
(ev) => {
ev.preventDefault();
const code = ed.getValue();
if (copyToClipboard(code)) {
notifications.success(
window.deps.translateString('core.copy.copied', 'Code copied to clipboard'),
);
} else {
notifications.error(
window.deps.translateString('core.error.failedToCopyCode', 'Failed to copy code'),
);
}
},
);
return ed;
};

Expand Down Expand Up @@ -520,28 +502,27 @@ export const createCodeToImageUI = async ({
});
});

const shareBtn = codeToImageContainer.querySelector<HTMLButtonElement>('#code-to-img-share-btn')!;
const btnText = isMobile()
? shareBtn.innerText
: window.deps.translateString('codeToImage.copyImage', 'Copy Image');
shareBtn.innerText = btnText;
const menu = codeToImageContainer.querySelector<HTMLElement>('#code-to-img-share-menu')!;
const menuBtn = codeToImageContainer.querySelector<HTMLElement>('#code-to-img-menu-btn')!;
eventsManager.addEventListener(menuBtn, 'click', () => {
const currentDisplay = menu.style.display;
menu.style.display = currentDisplay === 'block' ? 'none' : 'block';
});
eventsManager.addEventListener(document, 'click', (e) => {
// click outside handler
if (!menu || !menuBtn) return;
if (e.target !== menuBtn && !menuBtn.contains(e.target as Node)) {
menu.style.display = 'none';
}
});

const shareBtn = codeToImageContainer.querySelector<HTMLElement>('#code-to-img-share-btn')!;
eventsManager.addEventListener(shareBtn, 'click', () => {
shareBtn.disabled = true;
shareBtn.classList.add('disabled');
const btnText = shareBtn.innerText;
shareBtn.innerText = window.deps.translateString('core.generating', 'Generating...');
getImageUrl()
.then(async (dataUrl: string) => {
const blob = await fetch(dataUrl).then((res) => res.blob());
if (!isMobile()) {
const imageCopied = await copyImage(blob, formData.format || 'png');
if (imageCopied) {
notifications.success(
window.deps.translateString('core.copy.copiedImage', 'Image copied to clipboard.'),
);
return;
}
// else fallback to share image
}
const data = {
files: [
new File([blob], `${formData.fileName}.${formData.format || 'png'}`, {
Expand All @@ -558,12 +539,54 @@ export const createCodeToImageUI = async ({
);
})
.finally(() => {
shareBtn.disabled = false;
shareBtn.classList.remove('disabled');
shareBtn.innerText = btnText;
});
});

const copyImageBtn = codeToImageContainer.querySelector<HTMLElement>(
'#code-to-img-copy-img-btn',
)!;
eventsManager.addEventListener(copyImageBtn, 'click', () => {
const btnText = copyImageBtn.innerText;
copyImageBtn.innerText = window.deps.translateString('core.generating', 'Generating...');
getImageUrl()
.then(async (dataUrl: string) => {
const blob = await fetch(dataUrl).then((res) => res.blob());
const imageCopied = await copyImage(blob, formData.format || 'png');
if (imageCopied) {
notifications.success(
window.deps.translateString('core.copy.copiedImage', 'Image copied to clipboard.'),
);
return;
}
})
.catch(() => {
notifications.error(
window.deps.translateString('core.error.failedToCopyImage', 'Failed to copy image'),
);
})
.finally(() => {
copyImageBtn.innerText = btnText;
});
});

const copyCodeBtn = codeToImageContainer.querySelector<HTMLElement>(
'#code-to-img-copy-code-btn',
)!;
eventsManager.addEventListener(copyCodeBtn, 'click', (ev) => {
ev.preventDefault();
const code = editor.getValue();
if (copyToClipboard(code)) {
notifications.success(
window.deps.translateString('core.copy.copied', 'Code copied to clipboard'),
);
} else {
notifications.error(
window.deps.translateString('core.error.failedToCopyCode', 'Failed to copy code'),
);
}
});

const savedPreset = deps.getSavedPreset();
if (!savedPreset) {
applyPreset(presets[0]);
Expand Down
39 changes: 32 additions & 7 deletions src/livecodes/html/code-to-image.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="modal-screen-container">
<div class="modal-screen">
<label data-i18n="codeToImage.preview">Preview</label>
<a href="#" id="code-to-img-copy-link" class="code-link" data-i18n="codeToImage.copy">Copy</a>
<!-- <a href="#" id="code-to-img-copy-link" class="code-link" data-i18n="codeToImage.copy">Copy</a> -->
<!-- <a href="#" id="code-to-img-format-link" class="code-link" data-i18n="codeToImage.format">Format</a> -->
<div id="code-to-img-preview-background" dir="ltr">
<div id="code-to-img-preview-container"></div>
Expand Down Expand Up @@ -269,12 +269,37 @@
</div>
</div>
</form>
<button id="code-to-img-save-btn" class="wide-button" data-i18n="codeToImage.save">
Save Image
</button>
<button id="code-to-img-share-btn" class="wide-button" data-i18n="codeToImage.share">
Share Image
</button>
<div id="code-to-img-actions">
<button id="code-to-img-save-btn" class="wide-button" data-i18n="codeToImage.save">
Save Image
</button>
<button
id="code-to-img-menu-btn"
class="button"
title="Share"
data-i18n="app.share.hint"
data-i18n-prop="title"
>
<i class="icon-share"></i>
</button>
<div id="code-to-img-menu-container">
<ul id="code-to-img-share-menu" class="dropdown-menu">
<li>
<a href="#" id="code-to-img-share-btn" data-i18n="codeToImage.share">Share Image</a>
</li>
<li>
<a href="#" id="code-to-img-copy-img-btn" data-i18n="codeToImage.copyImage"
>Copy Image</a
>
</li>
<li>
<a href="#" id="code-to-img-copy-code-btn" data-i18n="codeToImage.copyCode"
>Copy Code</a
>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
8 changes: 6 additions & 2 deletions src/livecodes/i18n/locales/en/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -532,9 +532,9 @@
"notes": "",
"translation": "Code"
},
"codeToImage.copy": {
"codeToImage.copyCode": {
"notes": "",
"translation": "Copy"
"translation": "Copy Code"
},
"codeToImage.copyImage": {
"notes": "",
Expand Down Expand Up @@ -692,6 +692,10 @@
"notes": "",
"translation": "Failed to copy code"
},
"core.error.failedToCopyImage": {
"notes": "",
"translation": "Failed to copy image"
},
"core.error.failedToLoadTemplate": {
"notes": "",
"translation": "Failed loading template"
Expand Down
3 changes: 2 additions & 1 deletion src/livecodes/i18n/locales/en/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ const translation = {
background: 'Background',
borderRadius: 'Border Radius',
code: 'Code',
copy: 'Copy',
copyCode: 'Copy Code',
copyImage: 'Copy Image',
default: 'Default',
direction: 'Direction',
Expand Down Expand Up @@ -310,6 +310,7 @@ const translation = {
error: {
couldNotLoadTemplate: 'Could not load template: {{template}}',
failedToCopyCode: 'Failed to copy code',
failedToCopyImage: 'Failed to copy image',
failedToLoadTemplate: 'Failed loading template',
failedToLoadTemplates: 'Failed loading starter templates',
failedToParseSettings: 'Failed parsing settings as JSON',
Expand Down
36 changes: 36 additions & 0 deletions src/livecodes/styles/inc-modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1795,6 +1795,42 @@
width: 6em;
}
}

#code-to-img-actions {
display: flex;
gap: var(--s24);
width: 100%;
}

#code-to-img-menu-btn {
border-radius: 50%;
height: var(--s40);
min-width: 0;
width: var(--s40);
}

#code-to-img-menu-container {
flex-grow: 1;
position: relative;
}

#code-to-img-share-menu {
inset-inline-end: calc(100% + var(--s32) * 2);
min-width: 150px;
top: calc(-100% - var(--s20));
transform: translateX(100%);
width: fit-content;

a {
padding: var(--s12);
}
}

@media only screen and (max-width: 480px) {
#code-to-img-share-menu {
transform: translateX(var(--s40));
}
}
}

.accordion {
Expand Down

0 comments on commit b3b1555

Please sign in to comment.