Add many interactive components

- Version selector for MidnightLib is now finally working
- Added buttons to copy code from code blocks
- Added color chooser in Puzzle wiki
This commit is contained in:
Martin Prokoph
2024-09-18 01:19:42 +02:00
parent fc8286964f
commit 0c18baf478
5 changed files with 189 additions and 140 deletions

View File

@@ -0,0 +1,71 @@
---
interface Props {
includeHashtag?: boolean
}
const { includeHashtag } = Astro.props
import { Icon } from 'astro-icon/components'
---
<section class="my-6">
<div class="">
<p class="text-lg">Select a color below to get the hex code:</p>
<div class="flex">
<fieldset>
<input
type="color"
id="color-select"
class="h-16 w-48 hover:cursor-pointer rounded-xl border-neutral-900 dark:border-neutral-100 border-4"
/>
</fieldset>
<button
id="copy-button"
class="button has-icon color-secondary ml-3 rounded-md text-white hover:cursor-pointer appearance-none h-16">
<Icon id="copy-icon" name="ion:copy-outline" />
<Icon id="success-icon" name="ion:checkmark-outline" class="hidden" />
<p id="color-label">{includeHashtag ? '#' : ''}000000</p>
</div>
</div>
</section>
<script>
// Get the 2 elements from above
const colorLabel = document.getElementById("color-label");
const colorSelect = document.getElementById("color-select");
const copyButton = document.getElementById("copy-button");
const copyIcon = document.getElementById("copy-icon");
const successIcon = document.getElementById("success-icon");
colorSelect?.addEventListener("change", async (e) => {
const {
target: { value }, // Returns the chosen color (already in hex format :D)
} = e;
if (colorLabel) colorLabel.innerText = colorLabel.innerText.startsWith('#') ? value : value.replace('#', '');
});
// Add event listener to copy the color to the clipboard
if (colorLabel) copyButton?.addEventListener('click', () => copyString(colorLabel.innerText, copyButton));
async function copyString(text: string, button: HTMLElement) {
await navigator.clipboard.writeText(text);
// visual feedback that task is completed
if (button) {
button.style.backgroundColor = "#"+text.replace('#', '');
button.style.borderColor = "#"+text.replace('#', '');
}
if (copyIcon) copyIcon.style.display = 'none';
if (successIcon) successIcon.style.display = 'initial';
setTimeout(() => {
if (button) {
button.style.backgroundColor = 'var(--secondary-100)';
button.style.borderColor = 'var(--secondary-100)';
}
if (copyIcon) copyIcon.style.display = 'initial';
if (successIcon) successIcon.style.display = 'none';
}, 1000);
}
</script>

View File

@@ -1,161 +1,68 @@
---
import { loaderList, versionList, selectedLoader, selectedVersion, getResultingVersion } from '../js/modversion.js'
import { Icon } from 'astro-icon/components'
import { loaderList, versionList} from '../js/modversion.js'
---
<div id="version-dropdown">
<div class="container">
<div class="">
<div class="wrapper">
<label for="loader-selector" class="sr-only">Select the Modloader</label>
<select
x-data="{
loader: localStorage.selectedLoader || 'fabric',
switchLoader: function (newValue) {
localStorage.selectedLoader = newValue;
console.log('New loader: ' + localStorage.selectedLoader);
},
}"
name="loader-selector"
id="loader-selector"
class="appearance-none cursor-pointer rounded-md pl-3 pr-2 py-1.5 dark:bg-stone-950 dark:text-white focus-visible:outline-none"
x-model="loader"
aria-label="Choose the Modloader"
@change="switchLoader($event.target.value)">
class="selector cursor-pointer rounded-md pl-3 pr-2 py-1.5 border-2 dark:border-green-300 dark:bg-neutral-800 dark:text-white focus-visible:outline-none"
aria-label="Choose the Modloader">
{ loaderList.map((loader) =>
<option value={loader}>{loader.charAt(0).toUpperCase() + loader.slice(1)}</option>
<option value={loader}>{loader.charAt(0).toUpperCase() + loader.replace("neoforge", "NeoForge").slice(1)}</option>
)}
</select>
<label for="version-selector" class="sr-only">Select the Version</label>
<select
x-data="{
version: localStorage.selectedVersion || '1.21.1',
switchVersion: function (newValue) {
localStorage.selectedVersion = newValue;
console.log('New version: ' + localStorage.selectedVersion);
console.log(getResultingVersion);
},
}"
name="version-selector"
id="version-selector"
class="appearance-none cursor-pointer rounded-md pl-3 pr-2 py-1.5 dark:bg-stone-950 dark:text-white focus-visible:outline-none"
x-model="version"
aria-label="Choose the Version"
@change="switchVersion($event.target.value)">
class="selector cursor-pointer rounded-md ml-2 pl-3 pr-2 py-1.5 border-2 dark:border-green-300 dark:bg-neutral-800 dark:text-white focus-visible:outline-none"
aria-label="Choose the Version">
{ versionList.map((version) =>
<option value={version}>{version}</option>
)}
<Icon name="ion:copy-outline"></Icon>
</select>
<label for="version-selector" x-text="">{}</label>
</div>
</div>
</div>
<script>
import { getResultingVersion, setGameVersion, setLoaderVersion } from "../js/modversion";
// Get the gradle.properties code block
const versionLabel = document.getElementById("midnightlib-version");
// Get the 2 selectors defined above
const loaderSelector = document.getElementById("loader-selector");
const versionSelector = document.getElementById("version-selector");
loaderSelector?.addEventListener("change", async (e) => {
const {
target: { value }, // Returns the current loader string
} = e;
setLoaderVersion(value);
if (versionLabel) versionLabel.innerText = `midnightlib_version = `+getResultingVersion();
});
versionSelector?.addEventListener("change", async (e) => {
const {
target: { value }, // Returns the current version string
} = e;
setGameVersion(value);
if (versionLabel) versionLabel.innerText = `midnightlib_version = `+getResultingVersion();
});
</script>
<style lang="scss" is:global>
@use '../assets/scss/base/breakpoint' as *;
@use '../assets/scss/base/outline' as *;
#version-dropdown {
> .container {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.wrapper {
display: flex;
align-items: center;
gap: 1rem;
}
.wrapper {
> ul {
display: flex;
gap: 1.5rem;
list-style-type: none;
a,
button {
text-decoration: none;
font-size: 1.125rem;
line-height: 1.6875rem;
}
a:hover,
a:focus,
.is-active,
.has-version-dropdown > button:hover,
.has-version-dropdown > button:focus {
text-decoration: underline;
text-decoration-thickness: 1px;
text-decoration-style: wavy;
text-underline-offset: 7px;
}
.is-active {
font-weight: bold;
}
}
}
.has-version-dropdown {
position: relative;
> button {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0;
margin-top: -1px;
border: none;
color: var(--action-color);
&:hover {
color: var(--action-color-state);
&::after {
border-color: var(--action-color-state);
}
}
&::after {
content: '';
width: 0.85rem;
height: 0.75em;
margin-top: -0.25rem;
border-style: solid;
border-width: 0.2em 0.2em 0 0;
border-color: var(--action-color);
transform: rotate(135deg);
}
&.show {
&::after {
margin-top: 0.25rem;
transform: rotate(-45deg);
}
~ ul {
display: flex;
flex-direction: column;
gap: 1rem;
}
}
}
ul {
display: none;
position: absolute;
z-index: 100;
min-width: 260px;
top: 125%;
right: 0;
bottom: auto;
left: 0;
padding: 1rem;
background-color: var(--neutral-background);
border: 2px solid black;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}
}
#loader-selector::after {
content: "v";
}
.selector:is(.darkmode *) {
background-color: var(--dark-100);
}
</style>

View File

@@ -3,6 +3,44 @@ import DefaultLayout from './DefaultLayout.astro'
const { frontmatter } = Astro.props
---
<!-- Copy Code Buttons based on: https://timneubauer.dev/blog/copy-code-button-in-astro/ -->
<script>
let copyButtonLabel = "Copy Code";
let codeBlocks = Array.from(document.querySelectorAll("pre"));
for (let codeBlock of codeBlocks) {
let wrapper = document.createElement("div");
wrapper.style.position = "relative";
let copyButton = document.createElement("button");
copyButton.className = "copy-code";
copyButton.innerHTML = copyButtonLabel;
codeBlock.setAttribute("tabindex", "0");
codeBlock.appendChild(copyButton);
// wrap codebock with relative parent element
if (codeBlock.parentNode) codeBlock.parentNode.insertBefore(wrapper, codeBlock);
wrapper.appendChild(codeBlock);
copyButton.addEventListener("click", async () => {
await copyCode(codeBlock, copyButton);
});
}
async function copyCode(block, button) {
let code = block.querySelector("code");
let text = code.innerText;
await navigator.clipboard.writeText(text);
// visual feedback that task is completed
button.innerText = "Code Copied!";
setTimeout(() => {
button.innerText = copyButtonLabel;
}, 700);
}
</script>
<DefaultLayout title={frontmatter.title}>
<div class="container">
@@ -11,3 +49,35 @@ const { frontmatter } = Astro.props
</div>
</div>
</DefaultLayout>
<style is:global>
.copy-code {
position: absolute;
top: 0;
right: 0;
background-color: var(--primary-300);
color: var(--neutral-100);
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
line-height: 1rem;
border: none;
border-top-right-radius: 0.35rem;
border-bottom-left-radius: 0.35rem;
box-shadow: -1px 1px 8px var(--primary-300);
}
.copy-code:is(.darkmode *) {
background-color: var(--secondary-100);
color: var(--dark-100);
box-shadow: -1px 1px 8px var(--secondary-100);
}
.copy-code:hover {
background-color: var(--primary-500);
box-shadow: -1px 1px 8px var(--primary-500);
}
.copy-code:hover:is(.darkmode *) {
background-color: var(--secondary-500);
box-shadow: -1px 1px 8px var(--secondary-500);
}
</style>

View File

@@ -33,14 +33,13 @@ dependencies {
```
### `gradle.properties`
<VersionDropdown></VersionDropdown>
{<pre><code className="language-java">midnightlib_version = {getResultingVersion()}</code></pre>}
{<pre><code className="language-java" id="midnightlib-version" >midnightlib_version = {getResultingVersion()}</code></pre>}
<Notification type="info">
<Icon name="ion:information-circle-outline" />
<p>
<strong>Info:</strong> You should always pick the version that suits your modloader and Minecraft version best.
The version selector is currently still WIP.
Find all available versions on [Modrinth](https://www.modrinth.com/mod/midnightlib/versions)
The version selector is finally fully functional!
</p>
</Notification>

View File

@@ -3,6 +3,7 @@ layout: ../../layouts/MarkdownLayout.astro
title: Puzzle Wiki
---
import ColorPicker from '../../components/ColorPicker.astro'
import { Icon } from 'astro-icon/components'
import { Notification } from 'accessible-astro-components'
@@ -51,7 +52,7 @@ screen.loading.blend=off
### Entering the world of color
The world would be a sad place without colors.
That's why Puzzle allows you to customize them to your heart's content.
That's why Puzzle allows you to customize them to your heart's content!
Custom colors can be defined in the `assets/minecraft/optifine/color.properties` file.
```properties
@@ -69,11 +70,12 @@ screen.loading.bar=313244
<Notification type="default">
<Icon name="ion:information-circle-outline" />
<p>
<strong>Info:</strong> Colors have to be defined using hex color codes.
You can use websites like <strong>[this](https://redketchup.io/color-picker)</strong> one to find nice hex color codes.
<strong>Info:</strong> Colors have to be defined using hex color codes (without the #).
You can use the color picker below to find the perfect color.
The example colors are based on the <strong>[Catppuccin Mocha](https://github.com/catppuccin/catppuccin)</strong> color pallette.
</p>
</Notification>
<ColorPicker/>
<center><img alt="The Puzzle logo on a dark background with pastel colors" src="/puzzle/custom-colors.webp" width="650"></img></center>
<p class="text-center italic">Dark mode! Finally, my eyes can rest.</p>