mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
feat: improved dark mode color (#6616)
This commit is contained in:
@@ -54,7 +54,7 @@
|
||||
"scripts": {
|
||||
"setup": "node ./scripts/setup.js",
|
||||
"watch:converters": "npm run watch --workspace=packages/bruno-converters",
|
||||
"dev": "concurrently --kill-others \"npm run dev:web\" \"npm run dev:electron\"",
|
||||
"dev": "node ./scripts/dev.js",
|
||||
"watch": "npm run dev:watch",
|
||||
"dev:watch": "node ./scripts/dev-hot-reload.js",
|
||||
"dev:web": "npm run dev --workspace=packages/bruno-app",
|
||||
|
||||
3
packages/bruno-app/.gitignore
vendored
3
packages/bruno-app/.gitignore
vendored
@@ -34,4 +34,5 @@ yarn-error.log*
|
||||
.next/
|
||||
dist/
|
||||
|
||||
.env
|
||||
.env
|
||||
storybook-static/
|
||||
@@ -1,27 +1,27 @@
|
||||
import { rgba } from 'polished';
|
||||
import { rgba, lighten } from 'polished';
|
||||
|
||||
export const palette = {
|
||||
primary: {
|
||||
SOLID: 'hsl(39, 74%, 59%)',
|
||||
TEXT: 'hsl(39, 74%, 64%)',
|
||||
STRONG: 'hsl(39, 74%, 69%)',
|
||||
STRONG: 'hsl(39, 74%, 64%)',
|
||||
SUBTLE: 'hsl(39, 74%, 54%)'
|
||||
},
|
||||
hues: {
|
||||
RED: 'hsl(0, 70%, 71%)',
|
||||
ROSE: 'hsl(350, 65%, 78%)',
|
||||
BROWN: 'hsl(41, 52%, 77%)',
|
||||
ORANGE: 'hsl(24, 75%, 75%)',
|
||||
YELLOW: 'hsl(48, 68%, 74%)',
|
||||
LIME: 'hsl(75, 65%, 71%)',
|
||||
GREEN: 'hsl(140, 59%, 71%)',
|
||||
TEAL: 'hsl(170, 55%, 71%)',
|
||||
CYAN: 'hsl(190, 70%, 76%)',
|
||||
BLUE: 'hsl(202, 82%, 80%)',
|
||||
INDIGO: 'hsl(225, 73%, 82%)',
|
||||
VIOLET: 'hsl(260, 65%, 81%)',
|
||||
PURPLE: 'hsl(285, 60%, 78%)',
|
||||
PINK: 'hsl(320, 65%, 81%)'
|
||||
RED: 'hsl(8, 70%, 52%)',
|
||||
ROSE: 'hsl(367, 84%, 70%)',
|
||||
BROWN: 'hsl(35, 65%, 72%)',
|
||||
ORANGE: 'hsl(24, 88%, 72%)',
|
||||
YELLOW: 'hsl(41, 93%, 72%)',
|
||||
GREEN: 'hsl(140, 72%, 68%)',
|
||||
GREEN_DARK: 'hsl(160, 90%, 44%)',
|
||||
TEAL: 'hsl(170, 70%, 60%)',
|
||||
CYAN: 'hsl(190, 82%, 72%)',
|
||||
BLUE: 'hsl(210, 90%, 76%)',
|
||||
INDIGO: 'hsl(202, 88%, 66%)',
|
||||
VIOLET: 'hsl(260, 75%, 78%)',
|
||||
PURPLE: 'hsl(285, 72%, 75%)',
|
||||
PINK: 'hsl(305, 59%, 74%)'
|
||||
},
|
||||
system: {
|
||||
CONTROL_ACCENT: '#D9A342'
|
||||
@@ -64,17 +64,25 @@ palette.intent = {
|
||||
};
|
||||
|
||||
palette.syntax = {
|
||||
DEFINITION: palette.hues.GREEN,
|
||||
PROPERTY: palette.hues.BLUE,
|
||||
STRING: palette.hues.BROWN,
|
||||
NUMBER: palette.hues.GREEN,
|
||||
ATOM: palette.hues.YELLOW,
|
||||
VARIABLE: palette.hues.ROSE,
|
||||
// Core language structure
|
||||
KEYWORD: palette.hues.ROSE,
|
||||
COMMENT: palette.text.SUBTEXT1,
|
||||
OPERATOR: palette.hues.BROWN,
|
||||
TAG: palette.hues.ROSE,
|
||||
TAG_BRACKET: palette.text.SUBTEXT1
|
||||
// Identifiers & properties (collapsed)
|
||||
VARIABLE: palette.hues.PINK,
|
||||
PROPERTY: palette.hues.BLUE,
|
||||
DEFINITION: palette.hues.BLUE,
|
||||
|
||||
// Literals
|
||||
STRING: palette.hues.BROWN,
|
||||
NUMBER: palette.hues.PINK,
|
||||
ATOM: palette.hues.ROSE,
|
||||
|
||||
// Operators & punctuation (quiet)
|
||||
OPERATOR: palette.text.SUBTEXT1,
|
||||
TAG_BRACKET: palette.text.SUBTEXT1,
|
||||
|
||||
// Comments should recede
|
||||
COMMENT: palette.text.SUBTEXT0
|
||||
};
|
||||
|
||||
const colors = {
|
||||
@@ -230,13 +238,13 @@ const darkTheme = {
|
||||
get: palette.hues.GREEN,
|
||||
post: palette.hues.INDIGO,
|
||||
put: palette.hues.ORANGE,
|
||||
delete: palette.hues.RED,
|
||||
delete: lighten(0.08, palette.hues.RED),
|
||||
patch: palette.hues.ORANGE,
|
||||
options: palette.hues.TEAL,
|
||||
head: palette.hues.CYAN
|
||||
},
|
||||
|
||||
grpc: palette.hues.BROWN,
|
||||
grpc: palette.hues.TEAL,
|
||||
ws: palette.hues.ORANGE,
|
||||
gql: palette.hues.PINK
|
||||
},
|
||||
@@ -402,7 +410,7 @@ const darkTheme = {
|
||||
bg: palette.background.BASE
|
||||
},
|
||||
variable: {
|
||||
valid: palette.hues.GREEN,
|
||||
valid: palette.hues.GREEN_DARK,
|
||||
invalid: palette.hues.RED,
|
||||
prompt: palette.hues.BLUE
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@ const colors = {
|
||||
BORDER_LIGHT: '#3c3c3c',
|
||||
|
||||
CODEMIRROR_TOKENS: {
|
||||
DEFINITION: '#4ec9b0',
|
||||
DEFINITION: '#9cdcfe',
|
||||
PROPERTY: '#9cdcfe',
|
||||
STRING: '#ce9178',
|
||||
NUMBER: '#b5cea8',
|
||||
|
||||
@@ -62,17 +62,25 @@ palette.intent = {
|
||||
};
|
||||
|
||||
palette.syntax = {
|
||||
DEFINITION: palette.hues.INDIGO,
|
||||
PROPERTY: palette.hues.BLUE,
|
||||
STRING: palette.hues.BROWN,
|
||||
NUMBER: palette.hues.GREEN,
|
||||
ATOM: palette.hues.PURPLE,
|
||||
VARIABLE: palette.hues.PINK,
|
||||
// Core language structure
|
||||
KEYWORD: palette.hues.ROSE,
|
||||
COMMENT: palette.text.SUBTEXT0,
|
||||
OPERATOR: palette.hues.BLUE,
|
||||
TAG: palette.hues.ROSE,
|
||||
TAG_BRACKET: palette.text.SUBTEXT0
|
||||
// Identifiers & properties (collapsed)
|
||||
VARIABLE: palette.hues.PINK,
|
||||
PROPERTY: palette.hues.BLUE,
|
||||
DEFINITION: palette.hues.BLUE,
|
||||
|
||||
// Literals
|
||||
STRING: palette.hues.BROWN,
|
||||
NUMBER: palette.hues.PINK,
|
||||
ATOM: palette.hues.ROSE,
|
||||
|
||||
// Operators & punctuation (quiet)
|
||||
OPERATOR: palette.text.SUBTEXT1,
|
||||
TAG_BRACKET: palette.text.SUBTEXT1,
|
||||
|
||||
// Comments should recede
|
||||
COMMENT: palette.text.SUBTEXT0
|
||||
};
|
||||
|
||||
const lightTheme = {
|
||||
|
||||
@@ -195,8 +195,9 @@ app.on('ready', async () => {
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
const devPort = process.env.BRUNO_DEV_PORT || 3000;
|
||||
const url = isDev
|
||||
? 'http://localhost:3000'
|
||||
? `http://localhost:${devPort}`
|
||||
: format({
|
||||
pathname: path.join(__dirname, '../web/index.html'),
|
||||
protocol: 'file:',
|
||||
|
||||
99
scripts/dev.js
Normal file
99
scripts/dev.js
Normal file
@@ -0,0 +1,99 @@
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
// ANSI color codes
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
bright: '\x1b[1m',
|
||||
dim: '\x1b[2m',
|
||||
green: '\x1b[32m',
|
||||
yellow: '\x1b[33m',
|
||||
blue: '\x1b[34m',
|
||||
magenta: '\x1b[35m',
|
||||
cyan: '\x1b[36m',
|
||||
red: '\x1b[31m'
|
||||
};
|
||||
|
||||
const log = {
|
||||
info: (msg) => console.log(`${colors.cyan}ℹ${colors.reset} ${msg}`),
|
||||
success: (msg) => console.log(`${colors.green}✓${colors.reset} ${msg}`),
|
||||
warn: (msg) => console.log(`${colors.yellow}⚠${colors.reset} ${msg}`),
|
||||
error: (msg) => console.log(`${colors.red}✗${colors.reset} ${msg}`),
|
||||
label: (label, msg) => console.log(`${colors.bright}${colors.magenta}[${label}]${colors.reset} ${msg}`)
|
||||
};
|
||||
|
||||
const rootDir = path.join(__dirname, '..');
|
||||
const webDir = path.join(rootDir, 'packages/bruno-app');
|
||||
const electronDir = path.join(rootDir, 'packages/bruno-electron');
|
||||
|
||||
let electronProcess = null;
|
||||
let detectedPort = null;
|
||||
|
||||
// Regex to match rsbuild's local URL output (e.g., "➜ Local: http://localhost:3000/")
|
||||
const portRegex = /Local:\s+http:\/\/localhost:(\d+)/;
|
||||
|
||||
console.log(`\n${colors.bright}${colors.yellow}🚀 Starting Bruno development environment...${colors.reset}\n`);
|
||||
|
||||
// Start the rsbuild dev server
|
||||
const webProcess = spawn('npm', ['run', 'dev'], {
|
||||
cwd: webDir,
|
||||
stdio: ['inherit', 'pipe', 'pipe'],
|
||||
shell: true
|
||||
});
|
||||
|
||||
webProcess.stdout.on('data', (data) => {
|
||||
const output = data.toString();
|
||||
process.stdout.write(output);
|
||||
|
||||
// Try to detect the port from rsbuild output
|
||||
if (!detectedPort) {
|
||||
const match = output.match(portRegex);
|
||||
if (match) {
|
||||
detectedPort = match[1];
|
||||
log.success(`Detected dev server on port ${colors.bright}${detectedPort}${colors.reset}`);
|
||||
startElectron(detectedPort);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
webProcess.stderr.on('data', (data) => {
|
||||
process.stderr.write(data.toString());
|
||||
});
|
||||
|
||||
webProcess.on('close', (code) => {
|
||||
log.info(`Web process exited with code ${code}`);
|
||||
cleanup();
|
||||
});
|
||||
|
||||
function startElectron(port) {
|
||||
log.info(`Starting Electron with ${colors.cyan}BRUNO_DEV_PORT=${port}${colors.reset}`);
|
||||
|
||||
electronProcess = spawn('npm', ['run', 'dev'], {
|
||||
cwd: electronDir,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
env: {
|
||||
...process.env,
|
||||
BRUNO_DEV_PORT: port
|
||||
}
|
||||
});
|
||||
|
||||
electronProcess.on('close', (code) => {
|
||||
log.info(`Electron process exited with code ${code}`);
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
if (webProcess && !webProcess.killed) {
|
||||
webProcess.kill();
|
||||
}
|
||||
if (electronProcess && !electronProcess.killed) {
|
||||
electronProcess.kill();
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Handle termination signals
|
||||
process.on('SIGINT', cleanup);
|
||||
process.on('SIGTERM', cleanup);
|
||||
88
scripts/pr-checkout.js
Executable file
88
scripts/pr-checkout.js
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const prNumber = process.argv[2];
|
||||
|
||||
if (!prNumber || !/^\d+$/.test(prNumber)) {
|
||||
console.error('Usage: node scripts/pr-checkout.js <pr-number>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const repoRoot = path.resolve(__dirname, '..');
|
||||
const repoName = path.basename(repoRoot);
|
||||
const worktreesDir = path.resolve(repoRoot, '..', `${repoName}-worktrees`);
|
||||
const worktreePath = path.join(worktreesDir, `pr-${prNumber}`);
|
||||
|
||||
function log(...args) {
|
||||
console.error(...args);
|
||||
}
|
||||
|
||||
function run(cmd, options = {}) {
|
||||
log(`$ ${cmd}`);
|
||||
return execSync(cmd, { encoding: 'utf-8', cwd: repoRoot, stdio: 'inherit', ...options });
|
||||
}
|
||||
|
||||
function runCapture(cmd) {
|
||||
return execSync(cmd, { encoding: 'utf-8', cwd: repoRoot }).trim();
|
||||
}
|
||||
|
||||
// Check if gh CLI is available
|
||||
try {
|
||||
runCapture('gh --version');
|
||||
} catch {
|
||||
console.error('Error: GitHub CLI (gh) is not installed. Install it from https://cli.github.com/');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Get PR info
|
||||
log(`\nFetching PR #${prNumber} info...`);
|
||||
let prBranch, prHeadRepo;
|
||||
try {
|
||||
const prInfo = JSON.parse(runCapture(`gh pr view ${prNumber} --json headRefName,headRepository,headRepositoryOwner`));
|
||||
prBranch = prInfo.headRefName;
|
||||
prHeadRepo = `${prInfo.headRepositoryOwner.login}/${prInfo.headRepository.name}`;
|
||||
log(`PR branch: ${prBranch}`);
|
||||
log(`PR repo: ${prHeadRepo}`);
|
||||
} catch (error) {
|
||||
console.error(`Error: Could not fetch PR #${prNumber}. Make sure the PR exists and you're authenticated with gh.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if worktree already exists
|
||||
if (fs.existsSync(worktreePath)) {
|
||||
log(`\nWorktree already exists at ${worktreePath}`);
|
||||
log(`To remove it, run: git worktree remove ${worktreePath}`);
|
||||
console.log(worktreePath);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Create worktrees directory if needed
|
||||
if (!fs.existsSync(worktreesDir)) {
|
||||
log(`\nCreating worktrees directory: ${worktreesDir}`);
|
||||
fs.mkdirSync(worktreesDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Fetch the PR
|
||||
log(`\nFetching PR #${prNumber}...`);
|
||||
run(`gh pr checkout ${prNumber} --detach`, { stdio: 'pipe' });
|
||||
|
||||
// Get the current commit after checkout
|
||||
const prCommit = runCapture('git rev-parse HEAD');
|
||||
|
||||
// Go back to original branch
|
||||
const originalBranch = runCapture('git rev-parse --abbrev-ref @{-1} 2>/dev/null || git rev-parse --abbrev-ref HEAD');
|
||||
run(`git checkout ${originalBranch}`, { stdio: 'pipe' });
|
||||
|
||||
// Create the worktree
|
||||
log(`\nCreating worktree at ${worktreePath}...`);
|
||||
run(`git worktree add ${worktreePath} ${prCommit}`);
|
||||
|
||||
log(`\n✓ PR #${prNumber} checked out to: ${worktreePath}`);
|
||||
log(`\nTo remove the worktree later:`);
|
||||
log(` git worktree remove ${worktreePath}`);
|
||||
|
||||
// Output path to stdout for cd integration
|
||||
console.log(worktreePath);
|
||||
Reference in New Issue
Block a user