Restyle look and feel of the copy game link button

This commit is contained in:
sepia 2025-07-20 13:06:00 -05:00
parent badbe1f749
commit c112fa99cf
8 changed files with 99 additions and 27 deletions

View File

@ -23,9 +23,10 @@
<div id="messages" hx-swap-oob="beforeend"></div> <div id="messages" hx-swap-oob="beforeend"></div>
</div> </div>
<div id="game-link-container"> <div id="game-link-container">
Share link to this game: <button id="copy-link-button" onclick="copyGameLink()">
<input type="text" id="game-link" size="50" readonly /> <img src="/icons/clipboard-copy.svg" alt="Copy Game Link" class="icon" />
<button onclick="copyGameLink()">Copy</button> <span id="copy-link-text">Click to copy game link!</span>
</button>
</div> </div>
<div id="ws-status" style="margin-top: 10px; color: grey">Disconnected</div> <div id="ws-status" style="margin-top: 10px; color: grey">Disconnected</div>
<script src="scripts/display-ws-connection.js"></script> <script src="scripts/display-ws-connection.js"></script>

View File

@ -0,0 +1,3 @@
<svg data-slot="icon" aria-hidden="true" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0 0 15 2.25h-1.5a2.251 2.251 0 0 0-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9Z" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>

After

Width:  |  Height:  |  Size: 786 B

3
public/icons/copy-success.svg Executable file
View File

@ -0,0 +1,3 @@
<svg data-slot="icon" aria-hidden="true" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M11.35 3.836c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75 2.25 2.25 0 0 0-.1-.664m-5.8 0A2.251 2.251 0 0 1 13.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m8.9-4.414c.376.023.75.05 1.124.08 1.131.094 1.976 1.057 1.976 2.192V16.5A2.25 2.25 0 0 1 18 18.75h-2.25m-7.5-10.5H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V18.75m-7.5-10.5h6.375c.621 0 1.125.504 1.125 1.125v9.375m-8.25-3 1.5 1.5 3-3.75" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>

After

Width:  |  Height:  |  Size: 766 B

3
public/icons/edit.svg Executable file
View File

@ -0,0 +1,3 @@
<svg data-slot="icon" aria-hidden="true" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>

After

Width:  |  Height:  |  Size: 480 B

3
public/icons/heart.svg Executable file
View File

@ -0,0 +1,3 @@
<svg data-slot="icon" aria-hidden="true" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>

After

Width:  |  Height:  |  Size: 381 B

View File

@ -1,13 +1,30 @@
function copyGameLink() { function copyGameLink() {
const gameLinkInput = document.getElementById('game-link'); const gameId = document.querySelector('meta[name="gameId"]').content;
if (gameLinkInput) { const gameLink = `${window.location.origin}${window.location.pathname}?gameId=${gameId}`;
navigator.clipboard
.writeText(gameLinkInput.value) navigator.clipboard.writeText(gameLink)
.then(() => { .then(() => {
alert('Game link copied to clipboard!'); 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) => { .catch(err => {
console.error('Failed to copy link: ', err); console.error('Failed to copy link: ', err);
}); });
}
} }

View File

@ -19,13 +19,6 @@ gameContainer.setAttribute('ws-connect', wsUrl);
// Tell HTMX to connect the WebSocket // Tell HTMX to connect the WebSocket
htmx.trigger(gameContainer, ' and connect'); 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 // Update the WebSocket status indicator
const wsStatusDiv = document.getElementById('ws-status'); const wsStatusDiv = document.getElementById('ws-status');

View File

@ -9,6 +9,9 @@
--color-intersection-hover: rgba(255, 192, 203, 0.3); --color-intersection-hover: rgba(255, 192, 203, 0.3);
--color-heart-pink: #FFB6C1; --color-heart-pink: #FFB6C1;
--color-last-move-glow: rgba(255, 255, 0, 0.7); --color-last-move-glow: rgba(255, 255, 0, 0.7);
--color-black: #000;
--color-white: #fff;
--color-success-purple: #e0b0ff;
} }
body { body {
@ -33,14 +36,13 @@ body {
.game-board-grid { .game-board-grid {
position: relative; position: relative;
width: calc(14 * 30px); /* 14 gaps of 30px between 15 lines */ width: calc(14 * 30px);
height: calc(14 * 30px); /* 14 gaps of 30px between 15 lines */ height: calc(14 * 30px);
margin-top: 20px; margin-top: 20px;
background-color: var(--color-board-bg); background-color: var(--color-board-bg);
border: 2px solid var(--color-board-border); border: 2px solid var(--color-board-border);
} }
/* Grid lines */
.game-board-grid::before { .game-board-grid::before {
content: ''; content: '';
position: absolute; position: absolute;
@ -73,7 +75,6 @@ body {
background-color: var(--color-intersection-hover); background-color: var(--color-intersection-hover);
} }
/* Heart Stone Styling */
.stone-black-heart, .stone-white-heart { .stone-black-heart, .stone-white-heart {
position: relative; position: relative;
width: 24px; width: 24px;
@ -91,7 +92,7 @@ body {
width: 12px; width: 12px;
height: 20px; height: 20px;
border-radius: 50% 50% 0 0; 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; box-sizing: border-box;
transform: rotate(-45deg); transform: rotate(-45deg);
transform-origin: 0 100%; transform-origin: 0 100%;
@ -114,17 +115,65 @@ body {
background-color: var(--color-white); background-color: var(--color-white);
} }
.last-move { .last-move {
box-shadow: 0 0 5px 3px var(--color-last-move-glow); box-shadow: 0 0 5px 3px var(--color-last-move-glow);
} }
#messages { #messages {
margin-top: 10px; margin-top: 10px;
font-size: 0.9em; font-size: 0.9em;
color: var(--color-text-dark); color: var(--color-text-dark);
} }
#player-info { #player-info {
margin-top: 10px; margin-top: 10px;
font-weight: bold; font-weight: bold;
color: var(--color-text-dark); 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;
}