added encoding

main
czoczo 7 months ago
parent dfe71b4211
commit 22bc3162e7
  1. 310
      webpage/BetterBash/src/App.vue

@ -134,23 +134,63 @@
</div> </div>
</div> </div>
<div class="share-section">
<h3>Share Your Theme</h3>
<div class="share-url-container">
<input type="text" :value="shareableUrl" readonly id="shareUrlInput" @click="selectUrlText" />
<button @click="copyUrlToClipboard">Copy URL</button>
</div>
<p v-if="copySuccess" class="copy-success-message">Copied to clipboard!</p>
</div>
<div class="info-section"> <div class="info-section">
<h3>About This Customizer</h3> <h3>About This Customizer</h3>
<p> <p>
This tool allows you to customize the colors of your bash PS1 prompt. This tool allows you to customize the colors of your bash PS1 prompt.
Select different terminal colors for each component and individually toggle Select different terminal colors for each component and individually toggle
"light" (bright) or "bold" styles to see how they "light" (bright) or "bold" styles to see how they
look in the preview. look in the preview. You can share your theme using the URL generated above.
</p> </p>
<h3>Decoding the Share URL</h3>
<div class="decoding-explanation">
<p>The string after "betterba.sh/" in the URL is an 8-character code representing your theme. Here's how it works:</p>
<ol>
<li><strong>Fixed Order:</strong> Colors are encoded for 9 components in this fixed order:
Primary, Secondary, Root User, Time, Error Code, Separator, Border, Path, and Reset colors.</li>
<li><strong>Per-Component Encoding (5 bits):</strong>
<ul>
<li>Base Color (30-37) is mapped to 0-7 (3 bits).</li>
<li>Light State (normal/bright) is 0 or 1 (1 bit).</li>
<li>Bold State is 0 or 1 (1 bit).</li>
<li>These are combined: <code>(base_color_0_7 &lt;&lt; 2) | (light_bit &lt;&lt; 1) | bold_bit</code>.</li>
</ul>
</li>
<li><strong>Concatenation (45 bits):</strong> The 9 five-bit values are joined, forming a 45-bit sequence.</li>
<li><strong>Byte Packing (6 bytes):</strong> These 45 bits are packed into 6 bytes. The first 45 bits contain the data, and the last 3 bits of the 6th byte are zero-padded. Bits are packed MSB-first from the component data into the bytes.
<ul>
<li>Byte 1: <code>C1_b4 C1_b3 C1_b2 C1_b1 C1_b0 C2_b4 C2_b3 C2_b2</code></li>
<li>Byte 2: <code>C2_b1 C2_b0 C3_b4 C3_b3 C3_b2 C3_b1 C3_b0 C4_b4</code></li>
<li>Byte 3: <code>C4_b3 C4_b2 C4_b1 C4_b0 C5_b4 C5_b3 C5_b2 C5_b1</code></li>
<li>Byte 4: <code>C5_b0 C6_b4 C6_b3 C6_b2 C6_b1 C6_b0 C7_b4 C7_b3</code></li>
<li>Byte 5: <code>C7_b2 C7_b1 C7_b0 C8_b4 C8_b3 C8_b2 C8_b1 C8_b0</code></li>
<li>Byte 6: <code>C9_b4 C9_b3 C9_b2 C9_b1 C9_b0 0 0 0</code></li>
(<code>Cn_bx</code> is bit <code>x</code> of component <code>n</code>'s 5-bit value, <code>C1</code>=Primary, <code>C2</code>=Secondary, etc.)
</ul>
</li>
<li><strong>URL-Safe Base64:</strong> The 6 bytes are encoded using Base64, then <code>+</code> is replaced with <code>-</code>, <code>/</code> with <code>_</code>, and padding <code>=</code> are removed. This produces the 8-character code.</li>
</ol>
<p>To decode, reverse the process: Base64 decode, unpack bytes into 5-bit values, then extract base color, light, and bold states for each component.</p>
</div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed, onMounted } from 'vue'; // Added onMounted if needed for URL parsing later
// Color labels for UI // Color labels for UI - THE ORDER HERE IS IMPORTANT FOR `Object.keys(colorLabels)` if used
// but we'll use a hardcoded list for encoding/decoding for stability.
const colorLabels = { const colorLabels = {
PRIMARY_COLOR: 'Primary Color', PRIMARY_COLOR: 'Primary Color',
SECONDARY_COLOR: 'Secondary Color', SECONDARY_COLOR: 'Secondary Color',
@ -160,8 +200,19 @@ const colorLabels = {
SEPARATOR_COLOR: 'Separator Color', SEPARATOR_COLOR: 'Separator Color',
BORDCOL: 'Border Color', BORDCOL: 'Border Color',
PATH_COLOR: 'Path Color', PATH_COLOR: 'Path Color',
RST: 'Reset Color (e.g. "on", "=")',
}; };
// --- Hardcoded order for URL encoding/decoding stability ---
const ENCODING_ORDERED_COLOR_KEYS = [
'PRIMARY_COLOR', 'SECONDARY_COLOR', 'ROOT_COLOR', 'TIME_COLOR',
'ERR_COLOR', 'SEPARATOR_COLOR', 'BORDCOL', 'PATH_COLOR', 'RST'
];
if (ENCODING_ORDERED_COLOR_KEYS.length !== 9) {
console.error("Encoding logic assumes 9 color keys. Please update bit packing if this changes.");
}
// --- Base Color Definitions (30-37 range) --- // --- Base Color Definitions (30-37 range) ---
const baseColorDefinitions = { const baseColorDefinitions = {
30: { name: "Black", hex: "#000000", css: "text-black" }, 30: { name: "Black", hex: "#000000", css: "text-black" },
@ -192,25 +243,21 @@ const boldColorSpecifics = {
32: { hex: "#73d216", css: "text-bold-green" }, 32: { hex: "#73d216", css: "text-bold-green" },
33: { hex: "#edd400", css: "text-bold-yellow" }, 33: { hex: "#edd400", css: "text-bold-yellow" },
34: { hex: "#3584e4", css: "text-bold-blue" }, 34: { hex: "#3584e4", css: "text-bold-blue" },
35: { hex: "#ad7fa8", css: "text-bold-magenta" }, 35: { hex: "#ad7fa8", css: "text-bold-magenta" }, // Often same as bright in some terminals
36: { hex: "#34e2e2", css: "text-bold-cyan" }, 36: { hex: "#34e2e2", css: "text-bold-cyan" }, // Often same as bright
37: { hex: "#ffffff", css: "text-bold-white" }, 37: { hex: "#ffffff", css: "text-bold-white" }, // True white for bold light gray
90: { hex: "#7c7c7c", css: "text-bold-bright-black" }, 90: { hex: "#7c7c7c", css: "text-bold-bright-black" },
95: { hex: "#d070d0", css: "text-bold-bright-magenta" }, 95: { hex: "#d070d0", css: "text-bold-bright-magenta" },
97: { hex: "#ffffff", css: "text-bold-bright-white" }, 97: { hex: "#ffffff", css: "text-bold-bright-white" }, // True white for bold white
}; };
// --- Create a comprehensive map for lookup: codeNum-isBold -> {hex, cssClass} ---
const finalColorMappings = {}; const finalColorMappings = {};
// Normal (non-bold, non-light)
for (const code in baseColorDefinitions) { for (const code in baseColorDefinitions) {
finalColorMappings[`${code}-false`] = { hex: baseColorDefinitions[code].hex, cssClass: baseColorDefinitions[code].css }; finalColorMappings[`${code}-false`] = { hex: baseColorDefinitions[code].hex, cssClass: baseColorDefinitions[code].css };
} }
// Light (non-bold, light)
for (const code in lightColorDefinitions) { for (const code in lightColorDefinitions) {
finalColorMappings[`${code}-false`] = { hex: lightColorDefinitions[code].hex, cssClass: lightColorDefinitions[code].css }; finalColorMappings[`${code}-false`] = { hex: lightColorDefinitions[code].hex, cssClass: lightColorDefinitions[code].css };
} }
// Bold Normal
for (const code in baseColorDefinitions) { for (const code in baseColorDefinitions) {
const numCode = parseInt(code); const numCode = parseInt(code);
if (boldColorSpecifics[numCode] && !(numCode >= 90)) { if (boldColorSpecifics[numCode] && !(numCode >= 90)) {
@ -219,7 +266,6 @@ for (const code in baseColorDefinitions) {
finalColorMappings[`${numCode}-true`] = { hex: baseColorDefinitions[numCode].hex, cssClass: `${baseColorDefinitions[numCode].css} font-bold-style` }; finalColorMappings[`${numCode}-true`] = { hex: baseColorDefinitions[numCode].hex, cssClass: `${baseColorDefinitions[numCode].css} font-bold-style` };
} }
} }
// Bold Light
for (const code in lightColorDefinitions) { for (const code in lightColorDefinitions) {
const numCode = parseInt(code); const numCode = parseInt(code);
if (boldColorSpecifics[numCode]) { if (boldColorSpecifics[numCode]) {
@ -229,72 +275,59 @@ for (const code in lightColorDefinitions) {
} }
} }
// --- Options for Select Dropdowns ---
const baseColorOptions = Object.entries(baseColorDefinitions).map(([value, { name }]) => ({ const baseColorOptions = Object.entries(baseColorDefinitions).map(([value, { name }]) => ({
name, name,
value: parseInt(value), value: parseInt(value),
})); }));
// --- Initial state of selected color attributes for each prompt part ---
const initialBashColorCodes = { const initialBashColorCodes = {
PRIMARY_COLOR: '\\[\\033[00;92m\\]', PRIMARY_COLOR: '\\[\\033[00;92m\\]', // Bright Green
SECONDARY_COLOR: '\\[\\033[00;95;1m\\]', SECONDARY_COLOR: '\\[\\033[00;95;1m\\]', // Bold Bright Magenta
ROOT_COLOR: '\\[\\033[00;31;1m\\]', ROOT_COLOR: '\\[\\033[00;31;1m\\]', // Bold Red
TIME_COLOR: '\\[\\033[00;33;1m\\]', TIME_COLOR: '\\[\\033[00;33;1m\\]', // Bold Yellow
ERR_COLOR: '\\[\\033[00;31;1m\\]', ERR_COLOR: '\\[\\033[00;31;1m\\]', // Bold Red
SEPARATOR_COLOR: '\\[\\033[00;97;1m\\]', SEPARATOR_COLOR: '\\[\\033[00;97;1m\\]', // Bold White (Bright)
BORDCOL: '\\[\\033[00;90;1m\\]', BORDCOL: '\\[\\033[00;90;1m\\]', // Bold Bright Black (Gray)
PATH_COLOR: '\\[\\033[00;97;1m\\]', PATH_COLOR: '\\[\\033[00;97;1m\\]', // Bold White (Bright)
RST: '\\[\\033[00;37m\\]', RST: '\\[\\033[00;37m\\]', // Light Gray (Normal)
}; };
function parseInitialBashCodeToAttributes(bashCode) { function parseInitialBashCodeToAttributes(bashCode) {
// Regex to capture style (like '00'), color code, and optional bold marker ';1m' const match = bashCode.match(/\[(?:(\d{1,2}|[a-zA-Z]);)?(\d{2})(;1)?m/);
// Example: \[\\033[00;92m\] -> style: 00, colorNum: 92, boldSuffix: undefined let baseCode = 37;
// Example: \[\\033[00;31;1m\] -> style: 00, colorNum: 31, boldSuffix: ;1m
// Example: \[\\033[1;31m\] -> style: 1, colorNum: 31, boldSuffix: undefined (if we adapt to this)
const match = bashCode.match(/\[(?:(\d{1,2});)?(\d{2})(;1)?m/);
let baseCode = 37; // Default: Light Gray
let isLight = false; let isLight = false;
let isBold = false; let isBold = false;
if (match) { if (match) {
const stylePart = match[1]; // Might be undefined if only color code is present e.g. \[\033[32m\] const stylePart = match[1];
let colorNum = parseInt(match[2]); let colorNum = parseInt(match[2]);
const boldSuffix = match[3]; // ';1m' const boldSuffix = match[3];
isLight = colorNum >= 90 && colorNum <= 97; isLight = colorNum >= 90 && colorNum <= 97;
baseCode = isLight ? colorNum - 60 : colorNum; baseCode = isLight ? colorNum - 60 : colorNum;
// Determine boldness:
// 1. If there's a ';1m' suffix (specific to some original formats)
// 2. If the style part itself is '1' or '01' (standard bold)
isBold = !!boldSuffix || stylePart === '1' || stylePart === '01'; isBold = !!boldSuffix || stylePart === '1' || stylePart === '01';
} else { } else {
// Fallback for very simple codes like \[\033[32m\]
const simpleMatch = bashCode.match(/\[(\d{2})m/); const simpleMatch = bashCode.match(/\[(\d{2})m/);
if (simpleMatch) { if (simpleMatch) {
let colorNum = parseInt(simpleMatch[1]); let colorNum = parseInt(simpleMatch[1]);
isLight = colorNum >= 90 && colorNum <= 97; isLight = colorNum >= 90 && colorNum <= 97;
baseCode = isLight ? colorNum - 60 : colorNum; baseCode = isLight ? colorNum - 60 : colorNum;
isBold = false; // No bold info in this simple format isBold = false;
} }
} }
return { baseCode, isLight, isBold }; return { baseCode, isLight, isBold };
} }
const selectedColorAttributes = ref({}); const selectedColorAttributes = ref({});
for (const key in colorLabels) { ENCODING_ORDERED_COLOR_KEYS.forEach(key => {
if (initialBashColorCodes[key]) { if (initialBashColorCodes[key]) {
selectedColorAttributes.value[key] = parseInitialBashCodeToAttributes(initialBashColorCodes[key]); selectedColorAttributes.value[key] = parseInitialBashCodeToAttributes(initialBashColorCodes[key]);
} else { } else {
// Default for any new keys not in initialBashColorCodes selectedColorAttributes.value[key] = { baseCode: 37, isLight: false, isBold: false }; // Default
selectedColorAttributes.value[key] = { baseCode: 37, isLight: false, isBold: false };
}
} }
});
// --- Computed property to generate final Bash escape codes ---
const generatedColors = computed(() => { const generatedColors = computed(() => {
const finalCodes = {}; const finalCodes = {};
for (const key in selectedColorAttributes.value) { for (const key in selectedColorAttributes.value) {
@ -304,44 +337,49 @@ const generatedColors = computed(() => {
if (attrs.isBold) { if (attrs.isBold) {
finalCodes[key] = `\\[\\033[1;${actualCode}m\\]`; finalCodes[key] = `\\[\\033[1;${actualCode}m\\]`;
} else { } else {
finalCodes[key] = `\\[\\033[${actualCode}m\\]`; // Ensure "normal" style is explicit if no bold, using '0' or just the color
finalCodes[key] = `\\[\\033[0;${actualCode}m\\]`;
} }
} }
// Handle RST specifically if it shouldn't have complex styling (e.g. only \[\033[0m\] or \[\033[37m\])
// For this general tool, we keep RST configurable like others.
// If RST should always be \[\033[0m\], you can override:
// finalCodes['RST'] = '\\[\\033[0m\\]';
return finalCodes; return finalCodes;
}); });
// --- Helper function to parse generated Bash codes for preview ---
function parseGeneratedBashCode(bashCode) { function parseGeneratedBashCode(bashCode) {
const match = bashCode.match(/\[(?:(1);)?(\d{2})m/); const match = bashCode.match(/\[(?:(1);)?(\d{2})m/); // Bold group, color group
if (match) { if (match) {
const isBold = !!match[1]; const isBold = !!match[1];
const colorNum = parseInt(match[2]); const colorNum = parseInt(match[2]);
return { colorNum, isBold }; return { colorNum, isBold };
} }
const simplerMatch = bashCode.match(/\[(?:0;)?(\d{2})m/); // Try matching pattern like \[\033[0;32m\] or \[\033[0;92m\]
if (simplerMatch) { const nonBoldMatch = bashCode.match(/\[0;(\d{2})m/);
return { colorNum: parseInt(simplerMatch[1]), isBold: false }; if (nonBoldMatch) {
return { colorNum: parseInt(nonBoldMatch[1]), isBold: false };
}
// Try matching pattern like \[\033[32m\] (implicit normal)
const simplestMatch = bashCode.match(/\[(\d{2})m/);
if (simplestMatch) {
return { colorNum: parseInt(simplestMatch[1]), isBold: false };
} }
// Fallback if parsing fails, try to determine from current individual attribute
// This part is tricky as this function only gets the bash code, not the key.
// For robustness, stick to parsing the code or a safe default.
console.warn("Could not parse bash code for preview:", bashCode); console.warn("Could not parse bash code for preview:", bashCode);
return { colorNum: 37, isBold: false }; // Default to non-bold light gray return { colorNum: 37, isBold: false };
} }
// --- Get Hex Color for Preview Box ---
const getPreviewColorFromBash = (bashCode) => { const getPreviewColorFromBash = (bashCode) => {
if (!bashCode) return baseColorDefinitions[37].hex; // Default for undefined if (!bashCode) return baseColorDefinitions[37].hex;
const { colorNum, isBold } = parseGeneratedBashCode(bashCode); const { colorNum, isBold } = parseGeneratedBashCode(bashCode);
const mappingKey = `${colorNum}-${isBold}`; const mappingKey = `${colorNum}-${isBold}`;
const fallbackKeyNormal = `${colorNum}-false`; const fallbackKeyNormal = `${colorNum}-false`;
const colorData = finalColorMappings[mappingKey] || finalColorMappings[fallbackKeyNormal]; const colorData = finalColorMappings[mappingKey] || finalColorMappings[fallbackKeyNormal];
if (colorData) return colorData.hex; if (colorData) return colorData.hex;
return baseColorDefinitions[37].hex; // Ultimate fallback return baseColorDefinitions[37].hex;
}; };
// --- Get CSS Class for Prompt Preview ---
const getColorClassFromBash = (bashCode) => { const getColorClassFromBash = (bashCode) => {
if (!bashCode) return 'text-white'; if (!bashCode) return 'text-white';
const { colorNum, isBold } = parseGeneratedBashCode(bashCode); const { colorNum, isBold } = parseGeneratedBashCode(bashCode);
@ -355,13 +393,102 @@ const getColorClassFromBash = (bashCode) => {
if (normalData) { if (normalData) {
return isBold ? `${normalData.cssClass} font-bold-style` : normalData.cssClass; return isBold ? `${normalData.cssClass} font-bold-style` : normalData.cssClass;
} }
return 'text-white font-bold-style'; // Ultimate fallback return 'text-white font-bold-style';
}; };
const updatePromptDetails = () => { const updatePromptDetails = () => {
// console.log("Prompt attributes updated:", JSON.parse(JSON.stringify(selectedColorAttributes.value))); // This function is called on change, can be used for debugging or future enhancements
}; };
// --- URL Sharing Logic ---
function bytesToUrlSafeBase64(bytes) {
const base64 = btoa(String.fromCharCode(...bytes));
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
// function urlSafeBase64ToBytes(base64Str) { // For decoding if implemented
// let base64 = base64Str.replace(/-/g, '+').replace(/_/g, '/');
// const padding = base64.length % 4 === 0 ? '' : '='.repeat(4 - (base64.length % 4));
// const raw = atob(base64 + padding);
// const bytes = new Uint8Array(raw.length);
// for (let i = 0; i < raw.length; i++) {
// bytes[i] = raw.charCodeAt(i);
// }
// return bytes;
// }
function generateShareCode(selectedAttrs) {
const numParts = ENCODING_ORDERED_COLOR_KEYS.length;
if (numParts * 5 > 48) { // 45 bits for 9 parts, max 48 in 6 bytes
console.error("Too many parts for 6 bytes with 5 bits each");
return "";
}
const fiveBitValues = [];
for (const key of ENCODING_ORDERED_COLOR_KEYS) {
const attr = selectedAttrs[key];
if (!attr) { // Should not happen if selectedColorAttributes is initialized correctly
fiveBitValues.push(0); // Default: (0<<2)|0|0 = Black, not light, not bold
continue;
}
const shortBaseCode = attr.baseCode - 30; // 0-7
const lightBit = attr.isLight ? 1 : 0;
const boldBit = attr.isBold ? 1 : 0;
const value = (shortBaseCode << 2) | (lightBit << 1) | boldBit; // 0-31
fiveBitValues.push(value);
}
const bytes = new Uint8Array(6); // 48 bits
// Pack 9 * 5-bit values (45 bits) into 6 bytes
bytes[0] = (fiveBitValues[0] << 3) | (fiveBitValues[1] >> 2);
bytes[1] = ((fiveBitValues[1] & 0x03) << 6) | (fiveBitValues[2] << 1) | (fiveBitValues[3] >> 4);
bytes[2] = ((fiveBitValues[3] & 0x0F) << 4) | (fiveBitValues[4] >> 1);
bytes[3] = ((fiveBitValues[4] & 0x01) << 7) | (fiveBitValues[5] << 2) | (fiveBitValues[6] >> 3);
bytes[4] = ((fiveBitValues[6] & 0x07) << 5) | (fiveBitValues[7]);
bytes[5] = (fiveBitValues[8] << 3); // Last 3 bits of this byte will be 0 (padding)
return bytesToUrlSafeBase64(bytes);
}
const shareableUrl = computed(() => {
const code = generateShareCode(selectedColorAttributes.value);
return `https://betterba.sh/${code}`;
});
const copySuccess = ref(false);
async function copyUrlToClipboard() {
try {
await navigator.clipboard.writeText(shareableUrl.value);
copySuccess.value = true;
setTimeout(() => {
copySuccess.value = false;
}, 2000);
} catch (err) {
console.error('Failed to copy URL: ', err);
alert('Failed to copy URL. Please copy it manually.');
}
}
function selectUrlText() {
const inputElement = document.getElementById('shareUrlInput');
if (inputElement) {
inputElement.select();
}
}
// Optional: Logic to parse code from URL on load
// onMounted(() => {
// const path = window.location.pathname;
// const parts = path.split('/');
// if (parts.length > 1 && parts[1]) { // e.g. /XyZ123Ab
// const code = parts[1];
// // const decodedAttributes = parseShareCode(code); // You'd need to implement this
// // if (decodedAttributes) {
// // selectedColorAttributes.value = decodedAttributes;
// // }
// }
// });
</script> </script>
<style scoped> <style scoped>
@ -381,7 +508,7 @@ body {
h1 { h1 {
text-align: center; text-align: center;
margin-bottom: 30px; margin-bottom: 30px;
color: #10b981; color: #10b981; /* A pleasant green */
} }
.customizer { .customizer {
display: flex; display: flex;
@ -390,7 +517,7 @@ h1 {
} }
.color-controls { .color-controls {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); /* Adjusted minmax for more space */ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px; gap: 20px;
} }
.color-select-group { .color-select-group {
@ -400,7 +527,7 @@ h1 {
padding: 15px; padding: 15px;
border-radius: 8px; border-radius: 8px;
font-family: Consolas, Monaco, 'Lucida Console', monospace; font-family: Consolas, Monaco, 'Lucida Console', monospace;
gap: 10px; /* Space between main selector and checkboxes */ gap: 10px;
} }
.color-selector-main label { .color-selector-main label {
margin-bottom: 8px; margin-bottom: 8px;
@ -419,14 +546,14 @@ h1 {
} }
.color-modifier-checkboxes { .color-modifier-checkboxes {
display: flex; display: flex;
gap: 15px; /* Space between Light and Bold checkboxes */ gap: 15px;
margin-top: 5px; margin-top: 5px;
} }
.color-modifier-checkboxes label { .color-modifier-checkboxes label {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
font-weight: normal; /* Normal weight for checkbox labels */ font-weight: normal;
} }
.color-modifier-checkboxes input[type="checkbox"] { .color-modifier-checkboxes input[type="checkbox"] {
margin-right: 4px; margin-right: 4px;
@ -454,18 +581,66 @@ h1 {
border: 1px solid #555; border: 1px solid #555;
vertical-align: middle; vertical-align: middle;
} }
.info-section { .info-section, .share-section {
margin-top: 30px; margin-top: 30px;
background-color: #2d2d2d; background-color: #2d2d2d;
padding: 15px; padding: 20px;
border-radius: 8px; border-radius: 8px;
} }
.info-section h3, .share-section h3 {
margin-top: 0;
color: #10b981;
}
.share-url-container {
display: flex;
gap: 10px;
align-items: center;
}
.share-url-container input[type="text"] {
flex-grow: 1;
padding: 8px;
background-color: #3a3a3a;
color: #f0f0f0;
border: 1px solid #555;
border-radius: 4px;
font-family: Consolas, Monaco, 'Lucida Console', monospace;
}
.share-url-container button {
padding: 8px 15px;
background-color: #10b981;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
.share-url-container button:hover {
background-color: #0da874;
}
.copy-success-message {
color: #8ae234; /* Bright Green */
font-size: 0.9em;
margin-top: 5px;
}
.decoding-explanation {
font-size: 0.9em;
line-height: 1.6;
}
.decoding-explanation ul {
padding-left: 20px;
}
.decoding-explanation code {
background-color: #3a3a3a;
padding: 2px 4px;
border-radius: 3px;
font-family: Consolas, Monaco, 'Lucida Console', monospace;
}
.font-bold-style { .font-bold-style {
font-weight: bold !important; font-weight: bold !important;
} }
/* Terminal text colors from original CSS */ /* Terminal text colors (unchanged) */
.text-black { color: #000000; } .text-black { color: #000000; }
.text-red { color: #cc0000; } .text-red { color: #cc0000; }
.text-green { color: #4e9a06; } .text-green { color: #4e9a06; }
@ -498,4 +673,5 @@ h1 {
.text-red-on-white { color: #ffffff; background-color: #c00; } .text-red-on-white { color: #ffffff; background-color: #c00; }
.text-reset { color: #d3d7cf; } .text-reset { color: #d3d7cf; }
</style> </style>

Loading…
Cancel
Save