Bladerunner (#67)

* Introduce bladerunner theme

* Light neon glow

* Fix build error

* Different logo font and glow

* Neon glow on hover

* Make the theme to be easter egg

* Toggle lights via header

* Minor fixes

* Fix lint errors
This commit is contained in:
Borys Levytskyi
2025-11-07 21:24:02 -05:00
committed by GitHub
parent ac83c1efeb
commit c4877ac376
16 changed files with 20206 additions and 120 deletions

21
AGENTS.md Normal file
View File

@@ -0,0 +1,21 @@
Agent Guidelines for This Repository
Scope
- These instructions apply to the entire repository.
Theme Styling Policy
- Centralize all theme-related CSS (e.g., `.light`, `.dark`, `.midnight`, `.bladerunner`, and future themes) in `src/index.css` only.
- Do NOT place theme-specific rules in component-scoped stylesheets (e.g., files under `src/shell/components/*.css`). Component CSS must remain theme-agnostic.
- If a component needs theme-dependent styling, add/adjust the selectors in `src/index.css` that target the components markup (e.g., `.app-root.<theme> .component-selector { ... }`).
- Prefer grouping theme rules together by theme block in `src/index.css` for readability and consistency.
Layout Rules
- Global layout modifiers that affect multiple views (e.g., centered vs. stretched layout) should also live in `src/index.css`.
Examples
- Good: `src/index.css``.bladerunner .top-links button { color: #ff7fb0 }`
- Avoid: `src/shell/components/TopLinks.css``.bladerunner .top-links button { ... }`
Testing
- After changing theme styles, verify all themes (Light/Dark/Midnight/Bladerunner) render legibly and that component CSS contains no theme-specific selectors.

90
TEMP_whats.tsx Normal file
View File

@@ -0,0 +1,90 @@
import React from 'react';
import CommandLink from '../../core/components/CommandLink';
import './WhatsNewResultView.css';
function WhatsnewResultView() {
return <div className="changelog">
<h3>Changelog</h3>
<div className='item item-new'>
<p>
<span className="soft date">Nov 6th, 2025</span> <br/>
<p>
Added a new <CommandLink text="bladerunner" /> theme inspired by neon cyberpunk aesthetics.
</p>
</p>
</div>
<div className='item item-new'>
<p>
<span className="soft date">May 10th, 2023</span> <br/>
<p>
Behold! After a long time of inactivity, BitwiseCmd is getting an update. Here is what changed:
</p>
<ul>
<li>Browser's JavaScript engine is no longer used for the execution of bitwise operations.
BitwiseCmd has its own shiny custom-built bitwise calculator that supports operations integer of different sizes (8,16,32, and 64 bits) as well as their signed and unsigned versions. <CommandLink text='Check it out!' command='-1b 255ub -1 4294967295u -1l 18446744073709551615u' />.
This calculator tries to follow the same behavior of bitwise operations as implemented in C.
This includes shifting an integer by the number of bytes equal to its size (spoiler: you get the same number, this is undefined behavior in C. Don't believe me? Check this <a href="https://codeyarns.com/tech/2004-12-20-c-shift-operator-mayhem.html#gsc.tab=0">link</a>).</li>
<li>A slightly improved UI</li>
</ul>
<p>I'm sure there will be some bugs following such a big update. I will do my best to fix them as they are found.</p>
<p>Many thanks to all people that submitted issues on GitHub. Your feedback is greatly appreciated. </p>
</p>
</div>
<div className='item'>
<span className="soft date">May 5th, 2023</span> <br/>
<p>
Fixed <a href="https://github.com/BorysLevytskyi/BitwiseCmd/issues/13">bug</a> with incorrect binary representation of 64-bit numbers.
</p>
</div>
<div className="item">
<p><span className="soft date">Jul 24th, 2021</span> <br/>
<ul>
<li>Added support of <code>vpc</code> command to see how VPC network address is divided between VPC, Subnets, and Hosts. Try it out: <CommandLink text="vpc 192.168.24.1/24" /></li>
<li>Added ability to remove individual results</li>
</ul>
</p>
</div>
<div className="item">
<span className="soft date">Jun 16th, 2021</span>
<p>
Added support of <code>subnet</code> command to display information about subnet IP address such. Try it out: <CommandLink text="subnet 192.168.24.1/14" />
</p>
</div>
<div className="item">
<span className="soft date">Jun 14th, 2021</span>
<p>
Added support of IP addresses and subnet mask notations. Try them out:
</p>
<ul>
<li>A single IP address <CommandLink text="127.0.0.1" /></li>
<li>Multiple IP addresses and subnet mask notations <CommandLink text="127.0.0.1 192.168.0.0/24" /></li>
</ul>
</div>
<div className="item">
<span className="soft date">Jun 6th, 2017</span>
<p>
Added <code><CommandLink text="guid" /></code> command. Use it for generating v4 GUIDs </p>
</div>
<div className="item">
<span className="soft date">May 27th, 2017</span>
<p>
Added support of binary number notation (e.g. <code><CommandLink text="0b10101" /></code>). </p>
</div>
<div className="item">
<span className="soft">May 20th, 2017</span>
<p>
A new <CommandLink text="Midnight" /> theme was added.
</p>
</div>
<div className="item">
<span className="soft">May 16th, 2017</span>
<p>
Complete rewrite using React. Please let me know if you have problems with this release by <a href="https://github.com/BorysLevytskyi/BitwiseCmd/issues">creating an issue</a> in Github Repo.
</p>
</div>
</div>;
}
export default WhatsnewResultView;

19662
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -126,7 +126,7 @@ class ExpressionElementTableRow extends React.Component<ExpressionElementRowProp
return <tr className={"row-with-bits " + css}>
<td className="sign">{sign}</td>
<td className="label">
{this.getLabel()}
<span>{this.getLabel()}</span>
</td>
<td className="bin">
<BinaryStringView

View File

@@ -11,7 +11,26 @@ html { height: 100% }
position: relative;
}
code { font-size: 1.2em; font-weight: bold; }
/* Centered vs stretched layout */
.app-root.layout-centered { }
/* Constrain and center top-level sections while keeping full-width theme background */
.app-root.layout-centered > * {
max-width: clamp(70rem, 92vw, 100rem);
margin-left: auto;
margin-right: auto;
}
/* Blade Runner theme overrides for Settings pane (centralized here per AGENTS.md) */
.app-root.bladerunner #settings button { color: #ffbf69 }
.app-root.layout-stretched {
max-width: none;
margin: 0;
}
/* Theme-scoped code styling to avoid cross-theme overrides */
.light code, .dark code, .midnight code, .bladerunner code { font-size: 1.2em; font-weight: bold; }
.icon { margin-right: 5px; vertical-align: middle; }
.header-cmd { color: #c5c5c5 }
@@ -30,8 +49,6 @@ code { font-size: 1.2em; font-weight: bold; }
.button svg { margin: 0; margin-right: 5px; }
.button-large { padding: 10px; }
.button:hover { background: rgba(255, 255, 255, 0.2);}
.expressionInput {
padding: 3px;
outline: none;
@@ -98,6 +115,14 @@ button.link-button {text-decoration: underline;}
margin-left: -20px;
}
/* When Settings is active (no .soft), remove any button border/outline */
.settings-button button,
.settings-button .command-link {
border: none;
outline: none;
box-shadow: none;
}
.undo button {
opacity: 0.4;
padding: 0;
@@ -123,7 +148,7 @@ button.link-button {text-decoration: underline;}
.light .hashLink, .light .hashLink:visited { color: #aaa; }
.light .hashLink:hover { color: #888 }
.light ul.top-links li:hover { background: #ddd }
.light .error { color: #da586d }
.light .error { color: #d83e8f }
.light button.btn { color: black}
.light button.btn:hover { background: #ddd}
.light button.btn:disabled { color: #888; background-color: inherit; }
@@ -133,6 +158,8 @@ button.link-button {text-decoration: underline;}
.light .button:hover { background: rgba(0, 0, 0, 0.2);}
.light .solid-border { border: solid 1px gray;}
.light .accent1-border { border-color:green}
.light .help code, .light .help code a { color:green}
.light .button:hover { background: rgba(255, 255, 255, 0.2);}
/* Dark */
.dark { background: #121212; color: white;}
@@ -147,12 +174,14 @@ button.link-button {text-decoration: underline;}
.dark .hashLink, .dark .hashLink:visited { color: #555 }
.dark .hashLink:hover { color: #999 }
.dark ul.top-links li:hover { background: #333 }
.dark .error { color: #da586d}
.dark .error { color: #d83e8f}
.dark button.btn { color: white}
.dark button.btn:hover { background: #333}
.dark button.btn:disabled { color: #999; background-color: inherit; }
.dark .accent1 { color:mediumseagreen}
.dark .accent1-border { border-color:mediumseagreen}
.dark .help code, .dark .help code a { color:mediumseagreen}
.dark .button:hover { background: rgba(255, 255, 255, 0.2);}
/*
Midnight Theme
@@ -171,13 +200,139 @@ button.link-button {text-decoration: underline;}
.midnight .hashLink, .midnight .hashLink:visited { color: #85a0ad }
.midnight .hashLink:hover { color: #9FBAC7 }
.midnight ul.top-links li:hover { background: #132537 }
.midnight .error { color:#da586d}
.midnight .error { color:#d83e8f}
.midnight .changelog .item-new .date { font-weight: bold }
.midnight button.btn { color: white}
.midnight button.btn:hover { background: #132537}
.midnight button.btn:disabled { color: #85a0ad; background-color: inherit; }
.midnight .accent1 { color:mediumseagreen}
.midnight .accent1-border { border-color:mediumseagreen}
.midnight .help code, .midnight .help code a { color:mediumseagreen}
.midnight .button:hover { background: rgba(255, 255, 255, 0.2);}
/*
Blade Runner Theme
*/
.bladerunner { background: #0b0f14; color: white }
.bladerunner .solid-background { background: #0b0f14; }
.bladerunner .header-cmd { color: #ff7fb0a8 !important; }
.bladerunner .lights-on .header-cmd { color: #ff7fb0 !important; }
/* Rule for element when it has both .header and .on */
.bladerunner .header.lights-on { text-shadow: 0 0 4px rgba(255, 127, 176, 0.35), 0 0 9px rgba(255, 127, 176, 0.22); }
.bladerunner .header h1 { text-transform: uppercase; color: #66d9e8a8; font-family: Impact, Verdana, sans-serif; cursor: pointer; position: relative; z-index: 1; letter-spacing: 0.02em; }
.bladerunner .header h1.lights-on { color: #66d9e8; text-shadow: 0 0 4px rgba(102, 217, 232, 0.35), 0 0 9px rgba(102, 217, 232, 0.22); }
.bladerunner .header h1.lights-on::after {
/* Neon-style halo: layered cyan + magenta radial glows */
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translate(-30%, -50%);
width: 20%;
height: 120%;
pointer-events: none;
z-index: 0;
background:
radial-gradient(ellipse at center,
rgba(102, 217, 232, 0.70) 0%,
rgba(102, 217, 232, 0.45) 22%,
rgba(0, 0, 0, 0) 60%),
radial-gradient(ellipse at center,
rgba(255, 127, 176, 0.55) 0%,
rgba(255, 127, 176, 0.35) 35%,
rgba(0, 0, 0, 0) 72%);
filter: blur(35px);
}
.bladerunner {color: #e6f0ff;}
.bladerunner .expression { color: white; }
.bladerunner .expressionInput { color: white; }
.bladerunner a, .bladerunner a:visited { color: #00d1f2; }
.bladerunner button { color: #00eaff; }
.bladerunner .indicator { color: #0e6e7e; }
.bladerunner .on { color: white; }
.bladerunner .prefix { color: #00d1f2 }
.bladerunner .other { color: #6c8497}
.bladerunner .label { color: #7ac9d6 }
.bladerunner .accent-background { background-color: #131a22; }
.bladerunner .hashLink:hover { color: #33e1ff }
.bladerunner .error { color:#d83e8f }
.bladerunner .changelog .item-new .date { font-weight: bold }
.bladerunner button.btn { color: #00eaff }
.bladerunner button.btn:hover { background: #11222c }
.bladerunner button.btn:disabled { color: #0e6e7e; background-color: inherit; }
.bladerunner .accent1 { color: mediumseagreen }
.bladerunner .accent1-border { border-color: mediumseagreen }
.bladerunner .button { border-color: #00eaff }
.bladerunner code { color: #e3a600 }
.bladerunner code a, .bladerunner code a:visited { color: #e3a600 }
.bladerunner .command-link { color: #5fc2e9 }
.bladerunner .command-link:hover,
.bladerunner .command-link:focus {
/* very dim magenta glow */
text-shadow: 0 0 2px rgba(255, 127, 176, 0.5);
}
.bladerunner .soft { color: #aebed0 }
.bladerunner .solid-border { background-color: #0e161d; border-color: #1f3b4a;}
.bladerunner .expressionInput {border-color: #1f3b4a;}
.bladerunner .expressionInput::placeholder {color: #7e95a7;}
.bladerunner .zero {color: #b9cfe2; }
.bladerunner .expression {color: #e6f0ff;}
.bladerunner .settings-button button {color: #b9cfe2;}
.bladerunner button.hashLink, .bladerunner a.hashLink, .bladerunner a.hashLink:visited { color: #52687b; }
.bladerunner button.hashLink:hover, .bladerunner a.hashLink:hover {
/* subtle glow derived from current hover color */
--text-shadow: 0 0 2px currentColor;
text-shadow:0 0 2px rgb(229, 33, 0.5);
color: #5fc2e9;
}
.bladerunner .cur { color: #6c8497; }
/* Blade Runner: subtle glow for SVG icons inside hash links on hover/focus */
.bladerunner .hashLink:hover .icon,
.bladerunner .hashLink:focus .icon,
.bladerunner .hashLink:hover svg,
.bladerunner .hashLink:focus svg {
filter: drop-shadow(0 0 2px currentColor);
}
/* Blade Runner: neon hover glow for top-links controls */
.bladerunner .top-links a, .bladerunner .top-links a:visited { color: #dce7f5 }
.bladerunner .top-links button { color: #dce7f5 }
.bladerunner .top-links a:hover,
.bladerunner .top-links a:focus,
.bladerunner .top-links button:hover,
.bladerunner .top-links button:focus {
/* very dim magenta glow */
text-shadow:0 0 2px rgb(229, 33, 0.5);
color: #FFBF00;
}
/* Blade Runner: add matching glow to SVG icons inside top-links on hover/focus */
.bladerunner .top-links a:hover .icon,
.bladerunner .top-links a:focus .icon,
.bladerunner .top-links button:hover .icon,
.bladerunner .top-links button:focus .icon,
.bladerunner .top-links a:hover svg,
.bladerunner .top-links a:focus svg,
.bladerunner .top-links button:hover svg,
.bladerunner .top-links button:focus svg {
color: amber !important;
filter: drop-shadow(0 0 2px rgba(255, 127, 176, 0.5));
}
.bladerunner .bladerunner-easter-egg {display: none;}
.bladerunner-easter-egg {
position: absolute;
right: 1em;
bottom: 1em;
opacity: 0.3;
}
.bladerunner-easter-egg:hover {
opacity: 1;
}
button {
border: none;
@@ -185,8 +340,25 @@ button {
cursor: pointer;
}
button:focus {outline:0;}
/* Remove blue focus ring from the Blade Runner easter egg button */
.bladerunner-easter-egg button:focus,
.bladerunner-easter-egg button:focus-visible {
outline: none !important;
box-shadow: none !important;
}
/* Anchor the Blade Runner easter egg to bottom-right regardless of scrolling */
.bladerunner-easter-egg {
position: fixed;
right: 20px;
bottom: 20px;
z-index: 1000;
}
/* Top Links Shrink */
@media (max-width: 800px) {
.top-links .link-text { display: none }

View File

@@ -11,7 +11,8 @@ export type PersistedAppData = {
donationClicked: boolean;
annotateTypes: boolean;
dimExtrBits: boolean;
cookieDisclaimerHidden: boolean
cookieDisclaimerHidden: boolean,
centeredLayout?: boolean
}
export type CommandResultView = {
@@ -41,6 +42,7 @@ export default class AppState {
annotateTypes: boolean = false;
dimExtraBits: boolean = false;
cookieDisclaimerHidden: boolean = false;
centeredLayout: boolean = true;
constructor(persistData: PersistedAppData, env: string) {
@@ -56,6 +58,7 @@ export default class AppState {
this.annotateTypes = !!persistData.annotateTypes;
this.dimExtraBits = !!persistData.dimExtrBits;
this.cookieDisclaimerHidden = !!persistData.cookieDisclaimerHidden
this.centeredLayout = (persistData.centeredLayout === undefined) ? true : !!persistData.centeredLayout;
}
addCommandResult(input: string, view: ViewFactory) {
@@ -93,7 +96,7 @@ export default class AppState {
setUiTheme(theme: string) {
this.uiTheme = theme;
this.triggerChanged();
this.triggerChanged();
}
toggleDebugMode() {
@@ -116,6 +119,11 @@ export default class AppState {
this.triggerChanged();
}
toggleCenteredLayout(value?: boolean) {
this.centeredLayout = value !== null && value !== undefined ? value : !this.centeredLayout;
this.triggerChanged();
}
registerVisit() {
this.pageVisitsCount++;
this.triggerChanged();
@@ -144,11 +152,12 @@ export default class AppState {
donationClicked: this.donationClicked,
annotateTypes: this.annotateTypes,
dimExtrBits: this.dimExtraBits,
cookieDisclaimerHidden: this.cookieDisclaimerHidden
cookieDisclaimerHidden: this.cookieDisclaimerHidden,
centeredLayout: this.centeredLayout
}
}
};
function generateKey(): number {
return Math.ceil(Math.random() * 10000000) ^ Date.now(); // Because why the hell not...
}
}

80
src/shell/Bladerunner.ts Normal file
View File

@@ -0,0 +1,80 @@
import AppState from "./AppState";
import log from 'loglevel';
const LIGHTS_ON_KEY = 'lightsOn';
const LIGHTS_ON_CLASS = 'lights-on';
const turnLightsOff = (): void => (getHeader()).classList.remove('lights-on')
const getLightIsOn = () : boolean => localStorage.getItem(LIGHTS_ON_KEY) !== 'false';
const setLightIsOn = (value: boolean) => localStorage.setItem(LIGHTS_ON_KEY, value.toString());
const getHeader = (): HTMLHeadElement => document.querySelector('.header h1')!;
const toggleLights = (): void => {
const header = getHeader();
const lightIsOn = header.classList.contains(LIGHTS_ON_CLASS);
setLightIsOn(!lightIsOn);
if (lightIsOn)
turnLightsOff();
else
turnLightsOnWithFlickering();
};
const turnLightsOnWithFlickering = (): void => {
const header = getHeader();
const flickers = [true, false, true, false, true, false, true];
log.info("Turning lights on with flickering");
flickers.forEach((flicker, index) => {
setTimeout(() => {
if (flicker)
header.classList.add(LIGHTS_ON_CLASS);
else
header.classList.remove(LIGHTS_ON_CLASS);
}, index * 100);
});
};
const startLightsIfWereOnAfterDelay = (): void => {
if (getLightIsOn())
setTimeout(turnLightsOnWithFlickering, 500);
else
log.info("Lights are off by user preference");
};
const addStateListener = (appState: AppState) => {
var oldTheme = appState.uiTheme;
appState.onChange(() => {
log.info("App state changed, checking for lights theme. Current theme: " + appState.uiTheme + ", old theme: " + oldTheme);
if(appState.uiTheme === 'bladerunner' && oldTheme !== 'bladerunner') {
log.info("Starting lights because bladerunner theme is active");
startLightsIfWereOnAfterDelay();
}
else if(oldTheme === "bladerunner" && appState.uiTheme !== 'bladerunner') {
turnLightsOff();
}
oldTheme = appState.uiTheme;
});
};
const start = (appState: AppState): void => {
if(appState.uiTheme === 'bladerunner')
startLightsIfWereOnAfterDelay();
else
turnLightsOff();
addStateListener(appState);
};
const BladerunnerApi = { start, toggleLights };
export default BladerunnerApi;

View File

@@ -11,7 +11,8 @@ const DEFAULT_DATA : PersistedAppData = {
donationClicked: false,
annotateTypes: false,
dimExtrBits: false,
cookieDisclaimerHidden: false
cookieDisclaimerHidden: false,
centeredLayout: true
}
const appStateStore = {
@@ -39,4 +40,4 @@ const appStateStore = {
}
};
export default appStateStore;
export default appStateStore;

View File

@@ -7,9 +7,10 @@ import DebugIndicators from './DebugIndicators';
import hash from '../../core/hash';
import TopLinks from './TopLinks';
import SettingsPane from './SettingsPane';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faGear } from '@fortawesome/free-solid-svg-icons';
import CommandLink from '../../core/components/CommandLink';
import { faGear, faPersonRunning } from '@fortawesome/free-solid-svg-icons';
import CookieDisclaimerFooter from './CookieDisclaimerFooter';
import bladerunner from '../Bladerunner';
type AppRootProps = {
@@ -19,7 +20,8 @@ type AppRootProps = {
type AppRootState = {
uiTheme: string,
emphasizeBytes: boolean,
commandResults: CommandResultView[]
commandResults: CommandResultView[],
centeredLayout: boolean
}
export default class AppRoot extends React.Component<AppRootProps, AppRootState> {
@@ -46,33 +48,48 @@ export default class AppRoot extends React.Component<AppRootProps, AppRootState>
return results;
}
componentDidMount(): void {
bladerunner.start(this.props.appState);
}
render() {
const enableNewUi = this.props.appState.env !== 'prod' || true;
const newUi = enableNewUi ? 'new-ui' : '';
const settingsCss = "settings-button" + (this.props.appState.showSettings ? '' : ' soft');
return <div className={`app-root ${this.state.uiTheme} ${newUi}`}>
<DebugIndicators appState={this.props.appState} />
<div className="header">
<h1>Bitwise<span className="header-cmd">Cmd</span>
</h1>
<TopLinks />
</div>
const layoutClass = this.state.centeredLayout ? 'layout-centered' : 'layout-stretched';
return <div className={`app-root ${this.state.uiTheme} ${newUi} ${layoutClass}`}>
<div className="header-pane">
<DebugIndicators appState={this.props.appState} />
<div className="header">
<h1 onClick={() => bladerunner.toggleLights()}>
Bitwise<span className="header-cmd">Cmd</span>
</h1>
<TopLinks />
</div>
<div className="expressionInput-container">
<InputBox onCommandEntered={(input) => cmd.execute(input)} />
<button className={settingsCss} title='Toggle Settings' type="button" onClick={() => this.props.appState.toggleShowSettings()}>
<FontAwesomeIcon icon={faGear} />
</button>
<div className="expressionInput-container">
<InputBox onCommandEntered={(input) => cmd.execute(input)} />
<span className={settingsCss}>
<CommandLink text="" command='settings' icon={faGear} />
</span>
</div>
</div>
{this.props.appState.showSettings ? <SettingsPane appState={this.props.appState} /> : null}
<div id="output">
{this.getResultViews()}
<div className="content-pane">
{this.props.appState.showSettings ? <SettingsPane appState={this.props.appState} /> : null}
<div id="output">
{this.getResultViews()}
</div>
</div>
<CookieDisclaimerFooter appState={this.props.appState} />
<div className="bladerunner-easter-egg">
<CommandLink text="" command='bladerunner-easter' icon={faPersonRunning} />
</div>
<CookieDisclaimerFooter appSate={this.props.appState} />
</div>;
}
}
}

View File

@@ -5,14 +5,14 @@ import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCaretDown, faCaretUp, faCircleXmark } from "@fortawesome/free-solid-svg-icons";
function CookieDisclaimerFooter(props: { appSate: AppState }): JSX.Element {
function CookieDisclaimerFooter(props: { appState: AppState }): JSX.Element {
const [expanded, setShowMore] = useState(false);
const longCss = expanded ? " expanded" : " collapsed";
const shortCss = expanded ? " collapsed" : " expanded";
const buttonText = expanded ? "Read Less" : "Read More";
if (props.appSate.cookieDisclaimerHidden)
if (props.appState.cookieDisclaimerHidden)
return <React.Fragment></React.Fragment>;
return <div className="cookie-disclaimer">
@@ -34,10 +34,10 @@ function CookieDisclaimerFooter(props: { appSate: AppState }): JSX.Element {
</div>
<div>
<p>
<button className="button" onClick={() => setShowMore(!expanded)}><FontAwesomeIcon icon={expanded ? faCaretDown : faCaretUp} />{buttonText}</button> <button className="button" onClick={() => props.appSate.setCookieDisclaimerHidden(true)}><FontAwesomeIcon icon={faCircleXmark} />Hide</button>
<button className="button" onClick={() => setShowMore(!expanded)}><FontAwesomeIcon icon={expanded ? faCaretDown : faCaretUp} />{buttonText}</button> <button className="button" onClick={() => props.appState.setCookieDisclaimerHidden(true)}><FontAwesomeIcon icon={faCircleXmark} />Hide</button>
</p>
</div>
</div>
}
export default CookieDisclaimerFooter;
export default CookieDisclaimerFooter;

View File

@@ -1,6 +1,5 @@
.help ul { list-style-type: none; margin: 0; margin-left: 10px; margin-top: 0.2em; padding: 0; }
.help li { padding: 1px; margin-bottom: 5px;}
.help code, .help code a { color:mediumseagreen}
.light .help code, .light .help code a { color:green}
.help p { margin-top: 0.5em }
.help .section {padding: 1em;}

View File

@@ -31,7 +31,7 @@ function HelpResultView() {
<ul>
<li><code><CommandLink text="light" /></code> set the Light color theme</li>
<li><code><CommandLink text="dark" /></code> set the Dark color theme</li>
<li><code><CommandLink text="midnight" /></code> set the Midnight color theme</li>
<li><code><CommandLink text="midnight" /></code> set the Midnight color theme</li>
</ul>
</div>
<div className="section">
@@ -63,7 +63,7 @@ function HelpResultView() {
</div>
</div>
<div className="section soft-border">
<div className="section-title soft">Supported Number Types <sup className='accent1'>NEW</sup></div>
<div className="section-title soft">Supported Number Types</div>
<p>
BitiwseCmd no longer uses the browser's JavaScript engine for the execution of bitwise operations. It has its own calculator implementation which brings supports bitwise operations on the following <i>signed</i> and <i>unsigned</i> data types:
</p>

View File

@@ -31,4 +31,8 @@
.settings-container .setting {
margin-bottom: 10px;
}
}
/* Theme-specific overrides belong in src/index.css per AGENTS.md */
/* Ensure Settings aligns with centered layout */
.app-root.layout-centered #settings.settings-container { display: block; }

View File

@@ -44,8 +44,18 @@ function SettingsPane(props : SettingsPaneProps) {
: "Information about the size of integers is hidden."}
</p>
</div>
<div className='setting'>
<button type="button" onClick={() => appState.toggleCenteredLayout()}>
<FontAwesomeIcon size='xl' icon={appState.centeredLayout ? faToggleOn : faToggleOff} /> Centered Layout
</button>
<p className='description'>
{appState.centeredLayout
? "Content is centered with wide side margins on large screens."
: "Content stretches to full width as before."}
</p>
</div>
</div>
</div>
}
export default SettingsPane;
export default SettingsPane;

View File

@@ -2,81 +2,90 @@ import React from 'react';
import CommandLink from '../../core/components/CommandLink';
import './WhatsNewResultView.css';
function WhatsnewResultView() {
return <div className="changelog">
<h3>Changelog</h3>
<div className='item item-new'>
<p>
<span className="soft date">May 10th, 2023</span> <br/>
<p>
Behold! After a long time of inactivity, BitwiseCmd is getting an update. Here is what changed:
</p>
<ul>
<li>Browser's JavaScript engine is no longer used for the execution of bitwise operations.
BitwiseCmd has its own shiny custom-built bitwise calculator that supports operations integer of different sizes (8,16,32, and 64 bits) as well as their signed and unsigned versions. <CommandLink text='Check it out!' command='-1b 255ub -1 4294967295u -1l 18446744073709551615u' />.
This calculator tries to follow the same behavior of bitwise operations as implemented in C.
This includes shifting an integer by the number of bytes equal to its size (spoiler: you get the same number, this is undefined behavior in C. Don't believe me? Check this <a href="https://codeyarns.com/tech/2004-12-20-c-shift-operator-mayhem.html#gsc.tab=0">link</a>).</li>
<li>A slightly improved UI</li>
</ul>
<p>I'm sure there will be some bugs following such a big update. I will do my best to fix them as they are found.</p>
<p>Many thanks to all people that submitted issues on GitHub. Your feedback is greatly appreciated. </p>
</p>
</div>
<div className='item'>
<span className="soft date">May 5th, 2023</span> <br/>
<p>
Fixed <a href="https://github.com/BorysLevytskyi/BitwiseCmd/issues/13">bug</a> with incorrect binary representation of 64-bit numbers.
</p>
</div>
<div className="item">
<p><span className="soft date">Jul 24th, 2021</span> <br/>
<ul>
<li>Added support of <code>vpc</code> command to see how VPC network address is divided between VPC, Subnets, and Hosts. Try it out: <CommandLink text="vpc 192.168.24.1/24" /></li>
<li>Added ability to remove individual results</li>
</ul>
</p>
</div>
<div className="item">
<span className="soft date">Jun 16th, 2021</span>
<p>
Added support of <code>subnet</code> command to display information about subnet IP address such. Try it out: <CommandLink text="subnet 192.168.24.1/14" />
</p>
</div>
<div className="item">
<span className="soft date">Jun 14th, 2021</span>
<p>
Added support of IP addresses and subnet mask notations. Try them out:
</p>
<ul>
<li>A single IP address <CommandLink text="127.0.0.1" /></li>
<li>Multiple IP addresses and subnet mask notations <CommandLink text="127.0.0.1 192.168.0.0/24" /></li>
</ul>
</div>
<div className="item">
<span className="soft date">Jun 6th, 2017</span>
<p>
Added <code><CommandLink text="guid" /></code> command. Use it for generating v4 GUIDs </p>
</div>
<div className="item">
<span className="soft date">May 27th, 2017</span>
<p>
Added support of binary number notation (e.g. <code><CommandLink text="0b10101" /></code>). </p>
</div>
<div className="item">
<span className="soft">May 20th, 2017</span>
<p>
A new <CommandLink text="Midnight" /> theme was added.
</p>
</div>
<div className="item">
<span className="soft">May 16th, 2017</span>
<p>
Complete rewrite using React. Please let me know if you have problems with this release by <a href="https://github.com/BorysLevytskyi/BitwiseCmd/issues">creating an issue</a> in Github Repo.
</p>
</div>
</div>;
function WhatsNewResultView() {
return <div className="changelog">
<h3>Changelog</h3>
<div className='item item-new'>
<p>
<span className="soft date">Nov 6th, 2025</span> <br />
</p>
<ul>
<li>Introduced a Centered Layout option that centers content on wide monitors; you can revert to the stretched layout in <CommandLink text="settings" />.</li>
</ul>
</div>
<div className='item'>
<p>
<span className="soft date">May 10th, 2023</span> <br />
<p>
Behold! After a long time of inactivity, BitwiseCmd is getting an update. Here is what changed:
</p>
<ul>
<li>The browser's JavaScript engine is no longer used for executing bitwise operations.
BitwiseCmd now has its own shiny, custom-built bitwise calculator that supports bitwise operations on integers of different sizes (8, 16, 32, and 64 bits), in both signed and unsigned variants. <CommandLink text='Check it out!' command='-1b 255ub -1 4294967295u -1l 18446744073709551615u' />&nbsp;
This calculator follows the behavior of bitwise operations as implemented in C, including edge cases.
For example, shifting an integer by a number of bits equal to its width is undefined behavior in C (see this <a href="https://codeyarns.com/tech/2004-12-20-c-shift-operator-mayhem.html#gsc.tab=0">link</a>).
</li>
<li>A slightly improved UI</li>
</ul>
<p>I'm sure there will be some bugs following such a big update. I will do my best to fix them as they are found.</p>
<p>Many thanks to everyone who submitted issues on GitHub. Your feedback is greatly appreciated.</p>
</p>
</div>
<div className='item'>
<span className="soft date">May 5th, 2023</span> <br />
<p>
Fixed a <a href="https://github.com/BorysLevytskyi/BitwiseCmd/issues/13">bug</a> with the binary representation of 64-bit numbers.
</p>
</div>
<div className="item">
<p><span className="soft date">Jul 24th, 2021</span> <br />
<ul>
<li>Added support for the <code>vpc</code> command to see how the VPC network address bits are divided between the VPC, subnets, and hosts. Try it out: <CommandLink text="vpc 192.168.24.1/24" /></li>
<li>Added the ability to remove individual results</li>
</ul>
</p>
</div>
<div className="item">
<span className="soft date">Jun 16th, 2021</span>
<p>
Added support for the <code>subnet</code> command to display subnet information (network address, broadcast address, etc.). Try it out: <CommandLink text="subnet 192.168.24.1/14" />
</p>
</div>
<div className="item">
<span className="soft date">Jun 14th, 2021</span>
<p>
Added support for IP addresses and subnet mask notation. Try them out:
</p>
<ul>
<li>A single IP address <CommandLink text="127.0.0.1" /></li>
<li>Multiple IP addresses and subnet mask notations <CommandLink text="127.0.0.1 192.168.0.0/24" /></li>
</ul>
</div>
<div className="item">
<span className="soft date">Jun 6th, 2017</span>
<p>
Added the <code><CommandLink text="guid" /></code> command. Use it to generate v4 GUIDs.</p>
</div>
<div className="item">
<span className="soft date">May 27th, 2017</span>
<p>
Added support of binary number notation (e.g. <code><CommandLink text="0b10101" /></code>). </p>
</div>
<div className="item">
<span className="soft">May 20th, 2017</span>
<p>
A new <CommandLink text="Midnight" /> theme was added.
</p>
</div>
<div className="item">
<span className="soft">May 16th, 2017</span>
<p>
Complete rewrite using React. Please let me know if you have problems with this release by <a href="https://github.com/BorysLevytskyi/BitwiseCmd/issues">creating an issue</a> in Github Repo.
</p>
</div>
</div>;
}
export default WhatsnewResultView;
export default WhatsNewResultView;

View File

@@ -24,6 +24,16 @@ const shellModule = {
cmd.command("dark", () => appState.setUiTheme('dark'));
cmd.command("light", () => appState.setUiTheme('light'));
cmd.command("midnight", () => appState.setUiTheme('midnight'));
cmd.command("settings", () => appState.toggleShowSettings());
cmd.command("bladerunner", () => {
appState.setUiTheme('bladerunner');
sendAnalyticsEvent({eventCategory: "UI", eventAction: "ThemeChanged", eventLabel: "bladerunner"});
});
cmd.command("bladerunner-easter", (c: CommandInput) => {
document.querySelector('.app-root')!.scrollTo(0, 0);
cmd.execute("bladerunner");
appState.addCommandResult(c.input, () => <TextResultView text="You've discovered the hidden Blade Runner theme. Next time, to activate this theme, use the command 'bladerunner'." />);
});
cmd.command("about", (c: CommandInput) => appState.addCommandResult(c.input, () => <AboutResultView />));
cmd.command("whatsnew", (c: CommandInput) => appState.addCommandResult(c.input, () => <WhatsnewResultView />));
cmd.command("guid", (c: CommandInput) => appState.addCommandResult(c.input, () => <TextResultView text={uuid()} />));
@@ -92,4 +102,6 @@ const shellModule = {
}
}
export default shellModule;
export default shellModule;