diff --git a/css/style.css b/css/style.css
index a1ff505..e59c158 100644
--- a/css/style.css
+++ b/css/style.css
@@ -210,33 +210,7 @@ button {
transition: all 0.3s;
}
-.copy-button {
- position: absolute;
- top: 8px;
- right: 8px;
- padding: 6px;
- width: 32px;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: var(--button-bg);
- border: 1px solid var(--input-border);
- border-radius: 4px;
- color: var(--text-color);
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.copy-button:hover {
- background: var(--button-hover-bg);
- border-color: var(--accent-color);
- color: var(--accent-color);
-}
-
-.copy-button:active {
- transform: translateY(1px);
-}
+/* Copy button styling moved to a single definition below */
button:hover {
background-color: var(--button-hover-bg);
@@ -390,21 +364,46 @@ button:hover {
position: absolute;
top: 8px;
right: 8px;
- padding: 8px;
+ padding: 6px;
background: var(--button-bg);
- border: none;
- border-radius: 6px;
+ border: 1px solid var(--input-border);
+ border-radius: 4px;
color: var(--text-color);
- opacity: 0.7;
+ opacity: 0.8;
+ cursor: pointer;
transition: all 0.2s ease;
+ width: 32px;
+ height: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10;
}
.copy-button:hover {
- opacity: 1;
background: var(--button-hover-bg);
- color: var(--main-bg-color);
+ border-color: var(--accent-color);
+ color: var(--accent-color);
+ opacity: 1;
}
+.copy-button:active {
+ transform: translateY(1px);
+}
+
+.decoded-message {
+ position: relative;
+ padding: 12px;
+ background: var(--input-bg);
+ border-radius: 4px;
+ margin-top: 12px;
+ border: 1px solid var(--input-border);
+ font-family: 'Fira Code', monospace;
+ word-break: break-word;
+}
+
+/* Copy button hover styling is defined above */
+
.form-group label {
display: flex;
align-items: center;
diff --git a/index.html b/index.html
index 49e3772..07f6cf4 100644
--- a/index.html
+++ b/index.html
@@ -101,7 +101,9 @@
@@ -115,7 +117,9 @@
>
{{ decodedMessage }}
-
+
@@ -161,7 +165,9 @@
v-model="transformOutput"
aria-label="Transformed text output"
>
-
+
diff --git a/js/app.js b/js/app.js
index a66788b..9e684d6 100644
--- a/js/app.js
+++ b/js/app.js
@@ -68,13 +68,13 @@ new Vue({
if (this.activeSteg === 'invisible') {
this.encodedMessage = window.steganography.encodeInvisible(this.emojiMessage);
- this.copyToClipboard(this.encodedMessage);
+ // Don't auto-copy to avoid clipboard permission errors
} else if (this.selectedCarrier) {
this.encodedMessage = window.steganography.encodeEmoji(
this.selectedCarrier.emoji,
this.emojiMessage
);
- this.copyToClipboard(this.encodedMessage);
+ // Don't auto-copy to avoid clipboard permission errors
}
},
autoDecode() {
@@ -88,7 +88,7 @@ new Vue({
if (result) {
this.decodedMessage = `Decoded (${result.method}): ${result.text}`;
- this.copyToClipboard(result.text);
+ // Don't auto-copy to avoid clipboard permission errors
} else {
this.decodedMessage = 'No encoded message detected';
}
@@ -101,35 +101,71 @@ new Vue({
async copyToClipboard(text) {
if (!text) return;
- try {
- await navigator.clipboard.writeText(text);
-
- // Show a brief notification
- const notification = document.createElement('div');
- notification.className = 'copy-notification';
- notification.innerHTML = ' Copied!';
- document.body.appendChild(notification);
-
- // Remove after animation
- setTimeout(() => {
- notification.classList.add('fade-out');
- setTimeout(() => document.body.removeChild(notification), 300);
- }, 1000);
- } catch (err) {
- console.error('Failed to copy text:', err);
- // Show error notification
- const notification = document.createElement('div');
- notification.className = 'copy-notification error';
- notification.innerHTML = ' Copy failed';
- document.body.appendChild(notification);
-
- setTimeout(() => {
- notification.classList.add('fade-out');
- setTimeout(() => document.body.removeChild(notification), 300);
- }, 1000);
+ // Don't auto-copy in preview/iframe environments to avoid permission errors
+ // Only copy when explicitly triggered by a button click
+ const isExplicitUserAction = event && event.isTrusted;
+
+ // Only try to copy if we're not in a restricted environment or it's a direct user action
+ if (isExplicitUserAction) {
+ try {
+ await navigator.clipboard.writeText(text);
+
+ // Show a success notification
+ this.showNotification(' Copied!', 'success');
+ } catch (err) {
+ console.warn('Clipboard access not available:', err);
+
+ // Try fallback method for copying (textarea method)
+ this.fallbackCopy(text);
+ }
}
},
+ fallbackCopy(text) {
+ try {
+ // Create temporary textarea
+ const textarea = document.createElement('textarea');
+ textarea.value = text;
+ textarea.style.position = 'fixed'; // Avoid scrolling to bottom
+ document.body.appendChild(textarea);
+ textarea.select();
+
+ // Try the copy command
+ const successful = document.execCommand('copy');
+
+ // Show appropriate notification
+ if (successful) {
+ this.showNotification(' Copied!', 'success');
+ } else {
+ this.showNotification(' Copy not supported', 'error');
+ }
+
+ // Clean up
+ document.body.removeChild(textarea);
+ } catch (err) {
+ console.warn('Fallback copy method failed:', err);
+ this.showNotification(' Copy not supported', 'error');
+ }
+ },
+
+ showNotification(message, type = 'success') {
+ // Create notification element
+ const notification = document.createElement('div');
+ notification.className = `copy-notification ${type}`;
+ notification.innerHTML = message;
+ document.body.appendChild(notification);
+
+ // Remove after animation
+ setTimeout(() => {
+ notification.classList.add('fade-out');
+ setTimeout(() => {
+ if (notification.parentNode) {
+ document.body.removeChild(notification);
+ }
+ }, 300);
+ }, 1000);
+ },
+
// Universal Decoder - tries all decoding methods
universalDecode(input) {
if (!input) return '';