floatnote 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.beads/config.json +6 -0
- package/.beads/issues/floatnote-1.md +21 -0
- package/.beads/issues/floatnote-10.md +28 -0
- package/.beads/issues/floatnote-11.md +36 -0
- package/.beads/issues/floatnote-12.md +25 -0
- package/.beads/issues/floatnote-13.md +37 -0
- package/.beads/issues/floatnote-14.md +22 -0
- package/.beads/issues/floatnote-15.md +22 -0
- package/.beads/issues/floatnote-16.md +20 -0
- package/.beads/issues/floatnote-17.md +20 -0
- package/.beads/issues/floatnote-18.md +21 -0
- package/.beads/issues/floatnote-19.md +19 -0
- package/.beads/issues/floatnote-2.md +32 -0
- package/.beads/issues/floatnote-20.md +22 -0
- package/.beads/issues/floatnote-3.md +50 -0
- package/.beads/issues/floatnote-4.md +31 -0
- package/.beads/issues/floatnote-5.md +28 -0
- package/.beads/issues/floatnote-6.md +30 -0
- package/.beads/issues/floatnote-7.md +38 -0
- package/.beads/issues/floatnote-8.md +29 -0
- package/.beads/issues/floatnote-9.md +32 -0
- package/CLAUDE.md +61 -0
- package/README.md +95 -0
- package/bin/floatnote.js +218 -0
- package/coverage/base.css +224 -0
- package/coverage/bin/floatnote.js.html +739 -0
- package/coverage/bin/index.html +116 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +131 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/bin/floatnote.js.html +739 -0
- package/coverage/lcov-report/bin/index.html +116 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +131 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/index.html +146 -0
- package/coverage/lcov-report/src/main.js.html +1483 -0
- package/coverage/lcov-report/src/preload.js.html +361 -0
- package/coverage/lcov-report/src/renderer.js.html +8767 -0
- package/coverage/lcov.info +3273 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/index.html +146 -0
- package/coverage/src/main.js.html +1483 -0
- package/coverage/src/preload.js.html +361 -0
- package/coverage/src/renderer.js.html +8767 -0
- package/jest.config.js +48 -0
- package/package.json +59 -0
- package/src/icon-template.png +0 -0
- package/src/index.html +296 -0
- package/src/main.js +494 -0
- package/src/preload.js +96 -0
- package/src/renderer.js +3203 -0
- package/src/styles.css +1448 -0
- package/tests/cli/floatnote.test.js +167 -0
- package/tests/main/main.test.js +287 -0
- package/tests/mocks/electron.js +126 -0
- package/tests/mocks/fs.js +17 -0
- package/tests/preload/preload.test.js +218 -0
- package/tests/renderer/history.test.js +234 -0
- package/tests/renderer/notes.test.js +262 -0
- package/tests/renderer/settings.test.js +178 -0
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Floatnote
|
|
2
|
+
|
|
3
|
+
Transparent always-on-top drawing and note-taking overlay for macOS.
|
|
4
|
+
|
|
5
|
+
 
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### Using npx (recommended)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx floatnote
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This will automatically download and launch the latest version of Floatnote.
|
|
16
|
+
|
|
17
|
+
### Using Homebrew
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
brew tap josmanvis/floatnote
|
|
21
|
+
brew install --cask floatnote
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Manual Download
|
|
25
|
+
|
|
26
|
+
Download the latest release from [GitHub Releases](https://github.com/josmanvis/floatnote/releases).
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- **Transparent Overlay** - Draw on top of any application
|
|
31
|
+
- **Always on Top** - Never lose sight of your annotations
|
|
32
|
+
- **Drawing Tools** - Multiple colors and stroke sizes
|
|
33
|
+
- **Text Annotations** - Add text notes anywhere
|
|
34
|
+
- **Multi-note Support** - Create and navigate between multiple notes
|
|
35
|
+
- **Gesture Support** - Pinch to zoom, two-finger pan, rotate
|
|
36
|
+
- **Smart Paste** - Paste images directly from clipboard
|
|
37
|
+
- **Data Persistence** - Your notes are automatically saved
|
|
38
|
+
|
|
39
|
+
## Keyboard Shortcuts
|
|
40
|
+
|
|
41
|
+
| Action | Shortcut |
|
|
42
|
+
|--------|----------|
|
|
43
|
+
| Toggle Floatnote | `Cmd+Shift+G` |
|
|
44
|
+
| Quick Toggle | `Alt+Space` or `Ctrl+\`` |
|
|
45
|
+
| Settings | `Cmd+,` |
|
|
46
|
+
| Previous Note | `[` |
|
|
47
|
+
| Next Note | `]` |
|
|
48
|
+
| Undo | `Cmd+Z` |
|
|
49
|
+
| Redo | `Cmd+Shift+Z` |
|
|
50
|
+
| Select Mode | `V` |
|
|
51
|
+
| Draw Mode | `B` |
|
|
52
|
+
| Text Mode | `T` |
|
|
53
|
+
| Select All | `Cmd+A` |
|
|
54
|
+
| Delete | `D` |
|
|
55
|
+
| Zoom In | `Cmd++` |
|
|
56
|
+
| Zoom Out | `Cmd+-` |
|
|
57
|
+
| Reset Zoom | `Cmd+0` |
|
|
58
|
+
|
|
59
|
+
## CLI Options
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
floatnote [options]
|
|
63
|
+
|
|
64
|
+
Options:
|
|
65
|
+
-v, --version Show version number
|
|
66
|
+
-h, --help Show help message
|
|
67
|
+
--update Force update to latest version
|
|
68
|
+
--uninstall Remove Floatnote from your system
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## System Requirements
|
|
72
|
+
|
|
73
|
+
- macOS 10.13 or later
|
|
74
|
+
- Node.js 16+ (for npx installation)
|
|
75
|
+
|
|
76
|
+
## Development
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Clone the repository
|
|
80
|
+
git clone https://github.com/josmanvis/floatnote.git
|
|
81
|
+
cd floatnote
|
|
82
|
+
|
|
83
|
+
# Install dependencies
|
|
84
|
+
npm install
|
|
85
|
+
|
|
86
|
+
# Run in development mode
|
|
87
|
+
npm run dev
|
|
88
|
+
|
|
89
|
+
# Build for distribution
|
|
90
|
+
npm run build
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT
|
package/bin/floatnote.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const https = require('https');
|
|
7
|
+
const { createWriteStream, mkdirSync, existsSync, rmSync, unlinkSync, readFileSync, writeFileSync } = require('fs');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
|
|
10
|
+
const APP_NAME = 'Floatnote';
|
|
11
|
+
const GITHUB_REPO = 'josmanvis/floatnote';
|
|
12
|
+
const APP_DIR = path.join(process.env.HOME, '.floatnote');
|
|
13
|
+
const APP_PATH = path.join(APP_DIR, `${APP_NAME}.app`);
|
|
14
|
+
const VERSION_FILE = path.join(APP_DIR, 'version');
|
|
15
|
+
|
|
16
|
+
function log(message) {
|
|
17
|
+
console.log(`[floatnote] ${message}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function getLatestRelease() {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const options = {
|
|
23
|
+
hostname: 'api.github.com',
|
|
24
|
+
path: `/repos/${GITHUB_REPO}/releases/latest`,
|
|
25
|
+
headers: { 'User-Agent': 'floatnote-cli' }
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
https.get(options, (res) => {
|
|
29
|
+
if (res.statusCode === 404) {
|
|
30
|
+
reject(new Error('No releases found. Please wait for the first release to be published.'));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let data = '';
|
|
34
|
+
res.on('data', chunk => data += chunk);
|
|
35
|
+
res.on('end', () => {
|
|
36
|
+
try {
|
|
37
|
+
resolve(JSON.parse(data));
|
|
38
|
+
} catch (e) {
|
|
39
|
+
reject(new Error('Failed to parse release data'));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
res.on('error', reject);
|
|
43
|
+
}).on('error', reject);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function downloadFile(url, dest, onProgress) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const makeRequest = (requestUrl) => {
|
|
50
|
+
const parsedUrl = new URL(requestUrl);
|
|
51
|
+
const options = {
|
|
52
|
+
hostname: parsedUrl.hostname,
|
|
53
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
54
|
+
headers: { 'User-Agent': 'floatnote-cli' }
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
https.get(options, (res) => {
|
|
58
|
+
// Handle redirects
|
|
59
|
+
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
60
|
+
makeRequest(res.headers.location);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (res.statusCode !== 200) {
|
|
65
|
+
reject(new Error(`Download failed with status ${res.statusCode}`));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const totalSize = parseInt(res.headers['content-length'], 10);
|
|
70
|
+
let downloadedSize = 0;
|
|
71
|
+
|
|
72
|
+
const file = createWriteStream(dest);
|
|
73
|
+
res.on('data', (chunk) => {
|
|
74
|
+
downloadedSize += chunk.length;
|
|
75
|
+
if (onProgress && totalSize) {
|
|
76
|
+
const percent = Math.round((downloadedSize / totalSize) * 100);
|
|
77
|
+
onProgress(percent, downloadedSize, totalSize);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
res.pipe(file);
|
|
81
|
+
file.on('finish', () => {
|
|
82
|
+
file.close();
|
|
83
|
+
resolve();
|
|
84
|
+
});
|
|
85
|
+
file.on('error', (err) => {
|
|
86
|
+
unlinkSync(dest);
|
|
87
|
+
reject(err);
|
|
88
|
+
});
|
|
89
|
+
}).on('error', reject);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
makeRequest(url);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function formatBytes(bytes) {
|
|
97
|
+
if (bytes < 1024) return bytes + ' B';
|
|
98
|
+
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
99
|
+
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function main() {
|
|
103
|
+
// Handle command line arguments
|
|
104
|
+
const args = process.argv.slice(2);
|
|
105
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
106
|
+
const pkg = require('../package.json');
|
|
107
|
+
console.log(`floatnote v${pkg.version}`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
111
|
+
console.log(`
|
|
112
|
+
Floatnote - Transparent drawing overlay for macOS
|
|
113
|
+
|
|
114
|
+
Usage: floatnote [options]
|
|
115
|
+
|
|
116
|
+
Options:
|
|
117
|
+
-v, --version Show version number
|
|
118
|
+
-h, --help Show this help message
|
|
119
|
+
--update Force update to latest version
|
|
120
|
+
--uninstall Remove Floatnote from your system
|
|
121
|
+
|
|
122
|
+
Keyboard shortcuts (when app is running):
|
|
123
|
+
Cmd+Shift+G Toggle Floatnote
|
|
124
|
+
Alt+Space Quick toggle
|
|
125
|
+
Ctrl+\` Quick toggle
|
|
126
|
+
Cmd+, Settings
|
|
127
|
+
[ / ] Navigate notes
|
|
128
|
+
`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (args.includes('--uninstall')) {
|
|
133
|
+
if (existsSync(APP_DIR)) {
|
|
134
|
+
rmSync(APP_DIR, { recursive: true });
|
|
135
|
+
log('Floatnote has been uninstalled.');
|
|
136
|
+
} else {
|
|
137
|
+
log('Floatnote is not installed.');
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Create app directory
|
|
143
|
+
if (!existsSync(APP_DIR)) {
|
|
144
|
+
mkdirSync(APP_DIR, { recursive: true });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const forceUpdate = args.includes('--update');
|
|
148
|
+
let currentVersion = existsSync(VERSION_FILE) ? readFileSync(VERSION_FILE, 'utf8').trim() : null;
|
|
149
|
+
|
|
150
|
+
// Check for updates
|
|
151
|
+
try {
|
|
152
|
+
log('Checking for updates...');
|
|
153
|
+
const release = await getLatestRelease();
|
|
154
|
+
|
|
155
|
+
if (forceUpdate || !currentVersion || currentVersion !== release.tag_name || !existsSync(APP_PATH)) {
|
|
156
|
+
log(`Downloading Floatnote ${release.tag_name}...`);
|
|
157
|
+
|
|
158
|
+
// Find the zip asset for macOS
|
|
159
|
+
const zipAsset = release.assets.find(a =>
|
|
160
|
+
a.name.includes('mac') && a.name.endsWith('.zip') ||
|
|
161
|
+
a.name === `${APP_NAME}-${release.tag_name.replace('v', '')}-mac.zip` ||
|
|
162
|
+
a.name === `${APP_NAME}.zip` ||
|
|
163
|
+
a.name.endsWith('.zip')
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
if (!zipAsset) {
|
|
167
|
+
throw new Error('No macOS build found in the latest release.');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const zipPath = path.join(APP_DIR, 'floatnote.zip');
|
|
171
|
+
|
|
172
|
+
// Download with progress
|
|
173
|
+
let lastPercent = 0;
|
|
174
|
+
await downloadFile(zipAsset.browser_download_url, zipPath, (percent, downloaded, total) => {
|
|
175
|
+
if (percent !== lastPercent && percent % 10 === 0) {
|
|
176
|
+
log(`Progress: ${percent}% (${formatBytes(downloaded)} / ${formatBytes(total)})`);
|
|
177
|
+
lastPercent = percent;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Extract
|
|
182
|
+
log('Extracting...');
|
|
183
|
+
if (existsSync(APP_PATH)) {
|
|
184
|
+
rmSync(APP_PATH, { recursive: true });
|
|
185
|
+
}
|
|
186
|
+
execSync(`unzip -q -o "${zipPath}" -d "${APP_DIR}"`, { stdio: 'pipe' });
|
|
187
|
+
unlinkSync(zipPath);
|
|
188
|
+
|
|
189
|
+
// Save version
|
|
190
|
+
writeFileSync(VERSION_FILE, release.tag_name);
|
|
191
|
+
log(`Floatnote ${release.tag_name} installed successfully!`);
|
|
192
|
+
} else {
|
|
193
|
+
log(`Floatnote ${currentVersion} is up to date.`);
|
|
194
|
+
}
|
|
195
|
+
} catch (err) {
|
|
196
|
+
if (!existsSync(APP_PATH)) {
|
|
197
|
+
console.error(`Error: ${err.message}`);
|
|
198
|
+
console.error('Make sure the GitHub repository has published releases.');
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
// If app exists, we can still launch it
|
|
202
|
+
log(`Could not check for updates: ${err.message}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Launch the app
|
|
206
|
+
if (existsSync(APP_PATH)) {
|
|
207
|
+
log('Launching Floatnote...');
|
|
208
|
+
spawn('open', [APP_PATH], { detached: true, stdio: 'ignore' }).unref();
|
|
209
|
+
} else {
|
|
210
|
+
console.error('Error: Floatnote app not found. Please try running with --update flag.');
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
main().catch(err => {
|
|
216
|
+
console.error('Error:', err.message);
|
|
217
|
+
process.exit(1);
|
|
218
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
body, html {
|
|
2
|
+
margin:0; padding: 0;
|
|
3
|
+
height: 100%;
|
|
4
|
+
}
|
|
5
|
+
body {
|
|
6
|
+
font-family: Helvetica Neue, Helvetica, Arial;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
color:#333;
|
|
9
|
+
}
|
|
10
|
+
.small { font-size: 12px; }
|
|
11
|
+
*, *:after, *:before {
|
|
12
|
+
-webkit-box-sizing:border-box;
|
|
13
|
+
-moz-box-sizing:border-box;
|
|
14
|
+
box-sizing:border-box;
|
|
15
|
+
}
|
|
16
|
+
h1 { font-size: 20px; margin: 0;}
|
|
17
|
+
h2 { font-size: 14px; }
|
|
18
|
+
pre {
|
|
19
|
+
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
-moz-tab-size: 2;
|
|
23
|
+
-o-tab-size: 2;
|
|
24
|
+
tab-size: 2;
|
|
25
|
+
}
|
|
26
|
+
a { color:#0074D9; text-decoration:none; }
|
|
27
|
+
a:hover { text-decoration:underline; }
|
|
28
|
+
.strong { font-weight: bold; }
|
|
29
|
+
.space-top1 { padding: 10px 0 0 0; }
|
|
30
|
+
.pad2y { padding: 20px 0; }
|
|
31
|
+
.pad1y { padding: 10px 0; }
|
|
32
|
+
.pad2x { padding: 0 20px; }
|
|
33
|
+
.pad2 { padding: 20px; }
|
|
34
|
+
.pad1 { padding: 10px; }
|
|
35
|
+
.space-left2 { padding-left:55px; }
|
|
36
|
+
.space-right2 { padding-right:20px; }
|
|
37
|
+
.center { text-align:center; }
|
|
38
|
+
.clearfix { display:block; }
|
|
39
|
+
.clearfix:after {
|
|
40
|
+
content:'';
|
|
41
|
+
display:block;
|
|
42
|
+
height:0;
|
|
43
|
+
clear:both;
|
|
44
|
+
visibility:hidden;
|
|
45
|
+
}
|
|
46
|
+
.fl { float: left; }
|
|
47
|
+
@media only screen and (max-width:640px) {
|
|
48
|
+
.col3 { width:100%; max-width:100%; }
|
|
49
|
+
.hide-mobile { display:none!important; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.quiet {
|
|
53
|
+
color: #7f7f7f;
|
|
54
|
+
color: rgba(0,0,0,0.5);
|
|
55
|
+
}
|
|
56
|
+
.quiet a { opacity: 0.7; }
|
|
57
|
+
|
|
58
|
+
.fraction {
|
|
59
|
+
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
|
60
|
+
font-size: 10px;
|
|
61
|
+
color: #555;
|
|
62
|
+
background: #E8E8E8;
|
|
63
|
+
padding: 4px 5px;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
vertical-align: middle;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
div.path a:link, div.path a:visited { color: #333; }
|
|
69
|
+
table.coverage {
|
|
70
|
+
border-collapse: collapse;
|
|
71
|
+
margin: 10px 0 0 0;
|
|
72
|
+
padding: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
table.coverage td {
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 0;
|
|
78
|
+
vertical-align: top;
|
|
79
|
+
}
|
|
80
|
+
table.coverage td.line-count {
|
|
81
|
+
text-align: right;
|
|
82
|
+
padding: 0 5px 0 20px;
|
|
83
|
+
}
|
|
84
|
+
table.coverage td.line-coverage {
|
|
85
|
+
text-align: right;
|
|
86
|
+
padding-right: 10px;
|
|
87
|
+
min-width:20px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
table.coverage td span.cline-any {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
padding: 0 5px;
|
|
93
|
+
width: 100%;
|
|
94
|
+
}
|
|
95
|
+
.missing-if-branch {
|
|
96
|
+
display: inline-block;
|
|
97
|
+
margin-right: 5px;
|
|
98
|
+
border-radius: 3px;
|
|
99
|
+
position: relative;
|
|
100
|
+
padding: 0 4px;
|
|
101
|
+
background: #333;
|
|
102
|
+
color: yellow;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.skip-if-branch {
|
|
106
|
+
display: none;
|
|
107
|
+
margin-right: 10px;
|
|
108
|
+
position: relative;
|
|
109
|
+
padding: 0 4px;
|
|
110
|
+
background: #ccc;
|
|
111
|
+
color: white;
|
|
112
|
+
}
|
|
113
|
+
.missing-if-branch .typ, .skip-if-branch .typ {
|
|
114
|
+
color: inherit !important;
|
|
115
|
+
}
|
|
116
|
+
.coverage-summary {
|
|
117
|
+
border-collapse: collapse;
|
|
118
|
+
width: 100%;
|
|
119
|
+
}
|
|
120
|
+
.coverage-summary tr { border-bottom: 1px solid #bbb; }
|
|
121
|
+
.keyline-all { border: 1px solid #ddd; }
|
|
122
|
+
.coverage-summary td, .coverage-summary th { padding: 10px; }
|
|
123
|
+
.coverage-summary tbody { border: 1px solid #bbb; }
|
|
124
|
+
.coverage-summary td { border-right: 1px solid #bbb; }
|
|
125
|
+
.coverage-summary td:last-child { border-right: none; }
|
|
126
|
+
.coverage-summary th {
|
|
127
|
+
text-align: left;
|
|
128
|
+
font-weight: normal;
|
|
129
|
+
white-space: nowrap;
|
|
130
|
+
}
|
|
131
|
+
.coverage-summary th.file { border-right: none !important; }
|
|
132
|
+
.coverage-summary th.pct { }
|
|
133
|
+
.coverage-summary th.pic,
|
|
134
|
+
.coverage-summary th.abs,
|
|
135
|
+
.coverage-summary td.pct,
|
|
136
|
+
.coverage-summary td.abs { text-align: right; }
|
|
137
|
+
.coverage-summary td.file { white-space: nowrap; }
|
|
138
|
+
.coverage-summary td.pic { min-width: 120px !important; }
|
|
139
|
+
.coverage-summary tfoot td { }
|
|
140
|
+
|
|
141
|
+
.coverage-summary .sorter {
|
|
142
|
+
height: 10px;
|
|
143
|
+
width: 7px;
|
|
144
|
+
display: inline-block;
|
|
145
|
+
margin-left: 0.5em;
|
|
146
|
+
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
|
|
147
|
+
}
|
|
148
|
+
.coverage-summary .sorted .sorter {
|
|
149
|
+
background-position: 0 -20px;
|
|
150
|
+
}
|
|
151
|
+
.coverage-summary .sorted-desc .sorter {
|
|
152
|
+
background-position: 0 -10px;
|
|
153
|
+
}
|
|
154
|
+
.status-line { height: 10px; }
|
|
155
|
+
/* yellow */
|
|
156
|
+
.cbranch-no { background: yellow !important; color: #111; }
|
|
157
|
+
/* dark red */
|
|
158
|
+
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
|
|
159
|
+
.low .chart { border:1px solid #C21F39 }
|
|
160
|
+
.highlighted,
|
|
161
|
+
.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
|
|
162
|
+
background: #C21F39 !important;
|
|
163
|
+
}
|
|
164
|
+
/* medium red */
|
|
165
|
+
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
|
|
166
|
+
/* light red */
|
|
167
|
+
.low, .cline-no { background:#FCE1E5 }
|
|
168
|
+
/* light green */
|
|
169
|
+
.high, .cline-yes { background:rgb(230,245,208) }
|
|
170
|
+
/* medium green */
|
|
171
|
+
.cstat-yes { background:rgb(161,215,106) }
|
|
172
|
+
/* dark green */
|
|
173
|
+
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
|
|
174
|
+
.high .chart { border:1px solid rgb(77,146,33) }
|
|
175
|
+
/* dark yellow (gold) */
|
|
176
|
+
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
|
|
177
|
+
.medium .chart { border:1px solid #f9cd0b; }
|
|
178
|
+
/* light yellow */
|
|
179
|
+
.medium { background: #fff4c2; }
|
|
180
|
+
|
|
181
|
+
.cstat-skip { background: #ddd; color: #111; }
|
|
182
|
+
.fstat-skip { background: #ddd; color: #111 !important; }
|
|
183
|
+
.cbranch-skip { background: #ddd !important; color: #111; }
|
|
184
|
+
|
|
185
|
+
span.cline-neutral { background: #eaeaea; }
|
|
186
|
+
|
|
187
|
+
.coverage-summary td.empty {
|
|
188
|
+
opacity: .5;
|
|
189
|
+
padding-top: 4px;
|
|
190
|
+
padding-bottom: 4px;
|
|
191
|
+
line-height: 1;
|
|
192
|
+
color: #888;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.cover-fill, .cover-empty {
|
|
196
|
+
display:inline-block;
|
|
197
|
+
height: 12px;
|
|
198
|
+
}
|
|
199
|
+
.chart {
|
|
200
|
+
line-height: 0;
|
|
201
|
+
}
|
|
202
|
+
.cover-empty {
|
|
203
|
+
background: white;
|
|
204
|
+
}
|
|
205
|
+
.cover-full {
|
|
206
|
+
border-right: none !important;
|
|
207
|
+
}
|
|
208
|
+
pre.prettyprint {
|
|
209
|
+
border: none !important;
|
|
210
|
+
padding: 0 !important;
|
|
211
|
+
margin: 0 !important;
|
|
212
|
+
}
|
|
213
|
+
.com { color: #999 !important; }
|
|
214
|
+
.ignore-none { color: #999; font-weight: normal; }
|
|
215
|
+
|
|
216
|
+
.wrapper {
|
|
217
|
+
min-height: 100%;
|
|
218
|
+
height: auto !important;
|
|
219
|
+
height: 100%;
|
|
220
|
+
margin: 0 auto -48px;
|
|
221
|
+
}
|
|
222
|
+
.footer, .push {
|
|
223
|
+
height: 48px;
|
|
224
|
+
}
|