diff --git a/index.html b/index.html
index 6de1647..81b2f59 100644
--- a/index.html
+++ b/index.html
@@ -23,9 +23,10 @@
- Share link to this game:
-
-
+
Disconnected
diff --git a/public/icons/clipboard-copy.svg b/public/icons/clipboard-copy.svg
new file mode 100755
index 0000000..25b9ec7
--- /dev/null
+++ b/public/icons/clipboard-copy.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/public/icons/copy-success.svg b/public/icons/copy-success.svg
new file mode 100755
index 0000000..d81b72c
--- /dev/null
+++ b/public/icons/copy-success.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/public/icons/edit.svg b/public/icons/edit.svg
new file mode 100755
index 0000000..15bfee2
--- /dev/null
+++ b/public/icons/edit.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/public/icons/heart.svg b/public/icons/heart.svg
new file mode 100755
index 0000000..611c11e
--- /dev/null
+++ b/public/icons/heart.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/public/scripts/copy-game-link.js b/public/scripts/copy-game-link.js
index 6adcac4..1eaffc9 100644
--- a/public/scripts/copy-game-link.js
+++ b/public/scripts/copy-game-link.js
@@ -1,13 +1,30 @@
function copyGameLink() {
- const gameLinkInput = document.getElementById('game-link');
- if (gameLinkInput) {
- navigator.clipboard
- .writeText(gameLinkInput.value)
- .then(() => {
- alert('Game link copied to clipboard!');
- })
- .catch((err) => {
- console.error('Failed to copy link: ', err);
- });
- }
+ const gameId = document.querySelector('meta[name="gameId"]').content;
+ const gameLink = `${window.location.origin}${window.location.pathname}?gameId=${gameId}`;
+
+ navigator.clipboard.writeText(gameLink)
+ .then(() => {
+ const copyLinkButton = document.getElementById('copy-link-button');
+ const copyLinkText = document.getElementById('copy-link-text');
+ const originalIconSrc = '/icons/clipboard-copy.svg';
+ const originalTextContent = 'Click to copy game link!';
+
+ if (window.copyButtonTimeoutId) {
+ clearTimeout(window.copyButtonTimeoutId);
+ }
+
+ copyLinkButton.querySelector('img').src = '/icons/copy-success.svg';
+ copyLinkText.textContent = 'Game link copied!';
+ copyLinkButton.classList.add('copied-state');
+
+ window.copyButtonTimeoutId = setTimeout(() => {
+ copyLinkButton.querySelector('img').src = originalIconSrc;
+ copyLinkText.textContent = originalTextContent;
+ copyLinkButton.classList.remove('copied-state');
+ window.copyButtonTimeoutId = null;
+ }, 3000);
+ })
+ .catch(err => {
+ console.error('Failed to copy link: ', err);
+ });
}
diff --git a/public/scripts/display-ws-connection.js b/public/scripts/display-ws-connection.js
index 95ab2bc..e173b14 100644
--- a/public/scripts/display-ws-connection.js
+++ b/public/scripts/display-ws-connection.js
@@ -19,13 +19,6 @@ gameContainer.setAttribute('ws-connect', wsUrl);
// Tell HTMX to connect the WebSocket
htmx.trigger(gameContainer, ' and connect');
-// Update the game link input
-const gameLinkInput = document.getElementById('game-link');
-if (!gameLinkInput) {
- console.error('Missing game-link element.');
-}
-gameLinkInput.value =
- window.location.origin + window.location.pathname + `?gameId=${gameId}`;
// Update the WebSocket status indicator
const wsStatusDiv = document.getElementById('ws-status');
diff --git a/public/style.css b/public/style.css
index b131f99..c39e1c0 100644
--- a/public/style.css
+++ b/public/style.css
@@ -9,6 +9,9 @@
--color-intersection-hover: rgba(255, 192, 203, 0.3);
--color-heart-pink: #FFB6C1;
--color-last-move-glow: rgba(255, 255, 0, 0.7);
+ --color-black: #000;
+ --color-white: #fff;
+ --color-success-purple: #e0b0ff;
}
body {
@@ -33,14 +36,13 @@ body {
.game-board-grid {
position: relative;
- width: calc(14 * 30px); /* 14 gaps of 30px between 15 lines */
- height: calc(14 * 30px); /* 14 gaps of 30px between 15 lines */
+ width: calc(14 * 30px);
+ height: calc(14 * 30px);
margin-top: 20px;
background-color: var(--color-board-bg);
border: 2px solid var(--color-board-border);
}
-/* Grid lines */
.game-board-grid::before {
content: '';
position: absolute;
@@ -73,7 +75,6 @@ body {
background-color: var(--color-intersection-hover);
}
-/* Heart Stone Styling */
.stone-black-heart, .stone-white-heart {
position: relative;
width: 24px;
@@ -91,7 +92,7 @@ body {
width: 12px;
height: 20px;
border-radius: 50% 50% 0 0;
- border: 1px solid var(--color-black); /* Thin black outline - this creates the line through the middle */
+ border: 1px solid var(--color-black);
box-sizing: border-box;
transform: rotate(-45deg);
transform-origin: 0 100%;
@@ -114,17 +115,65 @@ body {
background-color: var(--color-white);
}
-
.last-move {
box-shadow: 0 0 5px 3px var(--color-last-move-glow);
}
+
#messages {
margin-top: 10px;
font-size: 0.9em;
color: var(--color-text-dark);
}
+
#player-info {
margin-top: 10px;
font-weight: bold;
color: var(--color-text-dark);
}
+
+#game-link-container {
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 40px;
+ margin-top: 20px;
+}
+
+#copy-link-button,
+#copy-success-message {
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ top: 0; bottom: 0;
+ transition: opacity 0.3s ease;
+ padding: 8px 15px;
+ border-radius: 5px;
+ white-space: nowrap;
+ box-sizing: border-box;
+}
+
+#copy-link-button {
+ background-color: var(--color-board-border);
+ color: var(--color-text-dark);
+ border: none;
+ cursor: pointer;
+ gap: 8px;
+ font-size: 1em;
+}
+
+#copy-link-button:hover {
+ background-color: var(--color-grid-lines);
+}
+
+#copy-link-button.copied-state {
+ background-color: var(--color-success-purple);
+}
+
+#copy-link-button img.icon {
+ width: 20px;
+ height: 20px;
+}