mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-12 19:48:44 +00:00
chore: set up commitlint, husky, and prettier (#1451)
* chore: add prettier configuration Signed-off-by: Xe Iaso <me@xeiaso.net> * format: run prettier tree-wide Signed-off-by: Xe Iaso <me@xeiaso.net> * chore(prettier): ignore intentionally ungrammatical files Signed-off-by: Xe Iaso <me@xeiaso.net> * ci: add PR title lint rule Signed-off-by: Xe Iaso <me@xeiaso.net> * ci: add DCO check Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: add commitlint and husky Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: add CONTRIBUTING guidelines Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: set SKIP_INTEGRATION in precommit tests Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: update spelling Signed-off-by: Xe Iaso <me@xeiaso.net> * ci(dco): remove reopened trigger Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: remove dead file Signed-off-by: Xe Iaso <me@xeiaso.net> * chore(prettier): don't format nginx includes Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
// A helper function to perform SHA-256 hashing.
|
||||
// It takes a string, encodes it, hashes it, and returns a hex string.
|
||||
async function sha256(message) {
|
||||
try {
|
||||
const msgBuffer = new TextEncoder().encode(message);
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
const hashHex = hashArray
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
return hashHex;
|
||||
} catch (error) {
|
||||
console.error("Hashing failed:", error);
|
||||
@@ -21,21 +23,42 @@ const generateRandomHex = (bytes = 16) => {
|
||||
const buffer = new Uint8Array(bytes);
|
||||
crypto.getRandomValues(buffer);
|
||||
return Array.from(buffer)
|
||||
.map(byte => byte.toString(16).padStart(2, '0'))
|
||||
.join('');
|
||||
.map((byte) => byte.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
};
|
||||
|
||||
|
||||
// Icon components for better visual feedback
|
||||
const CheckIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconGreen} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={styles.iconGreen}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
const XCircleIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconRed} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={styles.iconRed}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -46,7 +69,7 @@ export default function App() {
|
||||
// State for the nonce, which is the variable we can change
|
||||
const [nonce, setNonce] = useState(0);
|
||||
// State to store the resulting hash
|
||||
const [hash, setHash] = useState('');
|
||||
const [hash, setHash] = useState("");
|
||||
// A flag to indicate if the current hash is the "winning" one
|
||||
const [isMining, setIsMining] = useState(false);
|
||||
const [isFound, setIsFound] = useState(false);
|
||||
@@ -55,7 +78,10 @@ export default function App() {
|
||||
const difficulty = "00";
|
||||
|
||||
// Memoize the combined data to avoid recalculating on every render
|
||||
const combinedData = useMemo(() => `${challenge}${nonce}`, [challenge, nonce]);
|
||||
const combinedData = useMemo(
|
||||
() => `${challenge}${nonce}`,
|
||||
[challenge, nonce],
|
||||
);
|
||||
|
||||
// This effect hook recalculates the hash whenever the combinedData changes.
|
||||
useEffect(() => {
|
||||
@@ -68,7 +94,9 @@ export default function App() {
|
||||
}
|
||||
};
|
||||
calculateHash();
|
||||
return () => { isMounted = false; };
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [combinedData, difficulty]);
|
||||
|
||||
// This effect handles the automatic mining process
|
||||
@@ -93,7 +121,7 @@ export default function App() {
|
||||
// Update the UI periodically to avoid freezing the browser
|
||||
if (miningNonce % 100 === 0) {
|
||||
setNonce(miningNonce);
|
||||
await new Promise(resolve => setTimeout(resolve, 0)); // Yield to the browser
|
||||
await new Promise((resolve) => setTimeout(resolve, 0)); // Yield to the browser
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -102,28 +130,27 @@ export default function App() {
|
||||
|
||||
return () => {
|
||||
continueMining = false;
|
||||
}
|
||||
};
|
||||
}, [isMining, challenge, nonce, difficulty]);
|
||||
|
||||
|
||||
const handleMineClick = () => {
|
||||
setIsMining(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleStopClick = () => {
|
||||
setIsMining(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetClick = () => {
|
||||
setIsMining(false);
|
||||
setNonce(0);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNewChallengeClick = () => {
|
||||
setIsMining(false);
|
||||
setChallenge(generateRandomHex(16));
|
||||
setNonce(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper to render the hash with colored leading characters
|
||||
const renderHash = () => {
|
||||
@@ -153,12 +180,46 @@ export default function App() {
|
||||
<div className={styles.block}>
|
||||
<h2 className={styles.blockTitle}>2. Nonce</h2>
|
||||
<div className={styles.nonceControls}>
|
||||
<button onClick={() => setNonce(n => n - 1)} disabled={isMining} className={styles.nonceButton}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconSmall} fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 12H4" /></svg>
|
||||
<button
|
||||
onClick={() => setNonce((n) => n - 1)}
|
||||
disabled={isMining}
|
||||
className={styles.nonceButton}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={styles.iconSmall}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M20 12H4"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<span className={styles.nonceValue}>{nonce}</span>
|
||||
<button onClick={() => setNonce(n => n + 1)} disabled={isMining} className={styles.nonceButton}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconSmall} fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" /></svg>
|
||||
<button
|
||||
onClick={() => setNonce((n) => n + 1)}
|
||||
disabled={isMining}
|
||||
className={styles.nonceButton}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={styles.iconSmall}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -172,13 +233,26 @@ export default function App() {
|
||||
|
||||
{/* Arrow pointing down */}
|
||||
<div className={styles.arrowContainer}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={styles.iconGray} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={styles.iconGray}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M19 14l-7 7m0 0l-7-7m7 7V3"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Hash Output Block */}
|
||||
<div className={`${styles.hashContainer} ${isFound ? styles.hashContainerSuccess : styles.hashContainerError}`}>
|
||||
<div
|
||||
className={`${styles.hashContainer} ${isFound ? styles.hashContainerSuccess : styles.hashContainerError}`}
|
||||
>
|
||||
<div className={styles.hashContent}>
|
||||
<div className={styles.hashText}>
|
||||
<h2 className={styles.blockTitle}>4. Resulting Hash (SHA-256)</h2>
|
||||
@@ -193,18 +267,30 @@ export default function App() {
|
||||
{/* Mining Controls */}
|
||||
<div className={styles.buttonContainer}>
|
||||
{!isMining ? (
|
||||
<button onClick={handleMineClick} className={`${styles.button} ${styles.buttonCyan}`}>
|
||||
<button
|
||||
onClick={handleMineClick}
|
||||
className={`${styles.button} ${styles.buttonCyan}`}
|
||||
>
|
||||
Auto-Mine
|
||||
</button>
|
||||
) : (
|
||||
<button onClick={handleStopClick} className={`${styles.button} ${styles.buttonYellow}`}>
|
||||
<button
|
||||
onClick={handleStopClick}
|
||||
className={`${styles.button} ${styles.buttonYellow}`}
|
||||
>
|
||||
Stop Mining
|
||||
</button>
|
||||
)}
|
||||
<button onClick={handleNewChallengeClick} className={`${styles.button} ${styles.buttonIndigo}`}>
|
||||
<button
|
||||
onClick={handleNewChallengeClick}
|
||||
className={`${styles.button} ${styles.buttonIndigo}`}
|
||||
>
|
||||
New Challenge
|
||||
</button>
|
||||
<button onClick={handleResetClick} className={`${styles.button} ${styles.buttonGray}`}>
|
||||
<button
|
||||
onClick={handleResetClick}
|
||||
className={`${styles.button} ${styles.buttonGray}`}
|
||||
>
|
||||
Reset Nonce
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -48,7 +48,9 @@
|
||||
background-color: rgb(31 41 55);
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
box-shadow:
|
||||
0 10px 15px -3px rgb(0 0 0 / 0.1),
|
||||
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -158,7 +160,9 @@
|
||||
.hashContainer {
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
box-shadow:
|
||||
0 10px 15px -3px rgb(0 0 0 / 0.1),
|
||||
0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
transition: all 300ms;
|
||||
border: 2px solid;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user