Compare commits
10 commits
font-aweso
...
master
Author | SHA1 | Date | |
---|---|---|---|
Nick Krichevsky | dd648ee1f1 | ||
Nick Krichevsky | 731e15859b | ||
Nick Krichevsky | 31286f07ac | ||
Nick Krichevsky | 9eff40a12d | ||
Nick Krichevsky | c60f3d0f4f | ||
Nick Krichevsky | c6318cb8db | ||
Nick Krichevsky | c9ccd2a937 | ||
Nick Krichevsky | 580ad0296f | ||
Nick Krichevsky | 393bd4b4af | ||
Nick Krichevsky | 07b2ae37c7 |
|
@ -12,10 +12,8 @@
|
||||||
"one-var": ["error", "never"],
|
"one-var": ["error", "never"],
|
||||||
"quotes": ["error", "double"],
|
"quotes": ["error", "double"],
|
||||||
"semi": "error",
|
"semi": "error",
|
||||||
"space-before-function-paren": ["error", {"anonymous": "always", "named": "always", "asyncArrow": "always"}],
|
"space-before-function-paren": ["error", {"anonymous": "never", "named": "never", "asyncArrow": "always"}],
|
||||||
"space-before-blocks": ["error", "always"],
|
"space-before-blocks": ["error", "always"],
|
||||||
"space-infix-ops": "error"
|
"space-infix-ops": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: ft=json
|
|
94
gulpfile.js
94
gulpfile.js
|
@ -10,7 +10,6 @@ const gulpif = require("gulp-if");
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
const plumber = require("gulp-plumber");
|
const plumber = require("gulp-plumber");
|
||||||
const replaceExt = require("replace-ext");
|
const replaceExt = require("replace-ext");
|
||||||
const sequence = require("run-sequence");
|
|
||||||
const sass = require("gulp-sass");
|
const sass = require("gulp-sass");
|
||||||
const source = require("vinyl-source-stream");
|
const source = require("vinyl-source-stream");
|
||||||
const sourcemaps = require("gulp-sourcemaps");
|
const sourcemaps = require("gulp-sourcemaps");
|
||||||
|
@ -32,18 +31,25 @@ const FONT_AWESOME_OUT_DIR = "spectabular/webfonts";
|
||||||
|
|
||||||
//Map the various directories to the gulp tasks
|
//Map the various directories to the gulp tasks
|
||||||
const WATCH_MAPPINGS = {
|
const WATCH_MAPPINGS = {
|
||||||
[TS_SRC_DIR]: ["typescript-lint", "typescript"],
|
[TS_SRC_DIR]: ["typescript"],
|
||||||
[SASS_SRC_DIR]: ["sass"],
|
[SASS_SRC_DIR]: ["sass"],
|
||||||
[TWIG_SRC_DIR]: ["twig"],
|
[TWIG_SRC_DIR]: ["twig"],
|
||||||
};
|
};
|
||||||
|
|
||||||
let isProdBuild = yargs.argv.hasOwnProperty("prod");
|
let isProdBuild = yargs.argv.hasOwnProperty("prod");
|
||||||
|
|
||||||
gulp.task("build", (callback) => {
|
function buildAll(done) {
|
||||||
sequence("gulpfile-lint", "typescript-lint", "typescript", "fontawesome", "sass", "twig", callback);
|
return gulp.series(
|
||||||
});
|
"lint-gulpfile",
|
||||||
|
gulp.parallel(
|
||||||
|
"typescript",
|
||||||
|
"sass",
|
||||||
|
"twig",
|
||||||
|
"fontawesome"
|
||||||
|
)
|
||||||
|
)(done);
|
||||||
|
}
|
||||||
|
|
||||||
gulp.task("clean", () => {
|
function clean() {
|
||||||
return del([
|
return del([
|
||||||
JS_OUT_DIR,
|
JS_OUT_DIR,
|
||||||
CSS_OUT_DIR,
|
CSS_OUT_DIR,
|
||||||
|
@ -52,9 +58,9 @@ gulp.task("clean", () => {
|
||||||
].map((folder) => {
|
].map((folder) => {
|
||||||
return path.join(folder, "*");
|
return path.join(folder, "*");
|
||||||
}));
|
}));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task("watch", () => {
|
function watch(done) {
|
||||||
Object.keys(WATCH_MAPPINGS).forEach((dir) => {
|
Object.keys(WATCH_MAPPINGS).forEach((dir) => {
|
||||||
let globbedPath = path.join(dir, "*");
|
let globbedPath = path.join(dir, "*");
|
||||||
let tasks = WATCH_MAPPINGS[dir];
|
let tasks = WATCH_MAPPINGS[dir];
|
||||||
|
@ -64,15 +70,31 @@ gulp.task("watch", () => {
|
||||||
log(`[${chalk.blue(tasks.join(", "))}] Change detected: ${chalk.green(relativePath)}`);
|
log(`[${chalk.blue(tasks.join(", "))}] Change detected: ${chalk.green(relativePath)}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
gulp.task("typescript", (callback) => {
|
function lintGulpfile() {
|
||||||
|
return gulp.src("gulpfile.js")
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(eslint())
|
||||||
|
.pipe(eslint.format("stylish"))
|
||||||
|
.pipe(eslint.failAfterError());
|
||||||
|
}
|
||||||
|
|
||||||
|
function lintTypescript() {
|
||||||
|
return gulp.src(path.join(TS_SRC_DIR, "*.ts"))
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(tslint({
|
||||||
|
formatter: "stylish"
|
||||||
|
}))
|
||||||
|
.pipe(tslint.report());
|
||||||
|
}
|
||||||
|
|
||||||
|
function compileTypescript(done) {
|
||||||
let promises = TS_ENTRYPOINTS.map(async (entrypoint) => {
|
let promises = TS_ENTRYPOINTS.map(async (entrypoint) => {
|
||||||
let entrypointPath = path.join(TS_SRC_DIR, entrypoint);
|
let entrypointPath = path.join(TS_SRC_DIR, entrypoint);
|
||||||
let bundler = browserify(entrypointPath, {
|
let bundler = browserify(entrypointPath, {debug: !isProdBuild})
|
||||||
plugin: ["tsify"],
|
.plugin("tsify", {target: "ES2017"});
|
||||||
debug: !isProdBuild
|
|
||||||
});
|
|
||||||
let stream = plumber()
|
let stream = plumber()
|
||||||
.pipe(bundler.bundle())
|
.pipe(bundler.bundle())
|
||||||
.pipe(source(replaceExt(entrypoint, ".js")))
|
.pipe(source(replaceExt(entrypoint, ".js")))
|
||||||
|
@ -82,11 +104,11 @@ gulp.task("typescript", (callback) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all(promises).then(() => {
|
Promise.all(promises).then(() => {
|
||||||
callback();
|
done();
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task("sass", () => {
|
function compileSass() {
|
||||||
return gulp.src(path.join(SASS_SRC_DIR, "*.scss"))
|
return gulp.src(path.join(SASS_SRC_DIR, "*.scss"))
|
||||||
.pipe(plumber())
|
.pipe(plumber())
|
||||||
.pipe(sourcemaps.init())
|
.pipe(sourcemaps.init())
|
||||||
|
@ -95,34 +117,26 @@ gulp.task("sass", () => {
|
||||||
}).on("error", sass.logError))
|
}).on("error", sass.logError))
|
||||||
.pipe(gulpif(!isProdBuild, sourcemaps.write()))
|
.pipe(gulpif(!isProdBuild, sourcemaps.write()))
|
||||||
.pipe(gulp.dest(CSS_OUT_DIR));
|
.pipe(gulp.dest(CSS_OUT_DIR));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task("twig", () => {
|
function copyTwig() {
|
||||||
return gulp.src(path.join(TWIG_SRC_DIR, "*.{html,html.twig}"))
|
return gulp.src(path.join(TWIG_SRC_DIR, "*.{html,html.twig}"))
|
||||||
.pipe(gulp.dest(TWIG_OUT_DIR));
|
.pipe(gulp.dest(TWIG_OUT_DIR));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task("gulpfile-lint", () => {
|
function copyFontawesome() {
|
||||||
return gulp.src("gulpfile.js")
|
|
||||||
.pipe(plumber())
|
|
||||||
.pipe(eslint())
|
|
||||||
.pipe(eslint.format("stylish"))
|
|
||||||
.pipe(eslint.failAfterError());
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("typescript-lint", () => {
|
|
||||||
return gulp.src(path.join(TS_SRC_DIR, "*.ts"))
|
|
||||||
.pipe(plumber())
|
|
||||||
.pipe(tslint({
|
|
||||||
formatter: "stylish"
|
|
||||||
}))
|
|
||||||
.pipe(tslint.report());
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("fontawesome", () => {
|
|
||||||
return gulp.src([
|
return gulp.src([
|
||||||
path.join(FONT_AWESOME_BASE_DIR, "webfonts/*"),
|
path.join(FONT_AWESOME_BASE_DIR, "webfonts/*"),
|
||||||
path.join(FONT_AWESOME_BASE_DIR, "LICENSE.txt")
|
path.join(FONT_AWESOME_BASE_DIR, "LICENSE.txt")
|
||||||
])
|
])
|
||||||
.pipe(gulp.dest(FONT_AWESOME_OUT_DIR));
|
.pipe(gulp.dest(FONT_AWESOME_OUT_DIR));
|
||||||
});
|
}
|
||||||
|
|
||||||
|
gulp.task("typescript", gulp.series(lintTypescript, compileTypescript));
|
||||||
|
gulp.task("sass", compileSass);
|
||||||
|
gulp.task("twig", copyTwig);
|
||||||
|
gulp.task("fontawesome", copyFontawesome);
|
||||||
|
gulp.task("lint-gulpfile", lintGulpfile);
|
||||||
|
gulp.task(watch);
|
||||||
|
gulp.task("default", buildAll);
|
||||||
|
gulp.task(clean);
|
||||||
|
|
4653
package-lock.json
generated
4653
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -14,7 +14,7 @@
|
||||||
"del": "^3.0.0",
|
"del": "^3.0.0",
|
||||||
"eslint": "^5.0.1",
|
"eslint": "^5.0.1",
|
||||||
"fancy-log": "^1.3.2",
|
"fancy-log": "^1.3.2",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "^4.0.0",
|
||||||
"gulp-eslint": "^4.0.2",
|
"gulp-eslint": "^4.0.2",
|
||||||
"gulp-if": "^2.0.2",
|
"gulp-if": "^2.0.2",
|
||||||
"gulp-plumber": "^1.2.0",
|
"gulp-plumber": "^1.2.0",
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
@import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
|
||||||
|
@import "@fortawesome/fontawesome-free/scss/fa-solid.scss";
|
||||||
|
|
||||||
.tab-list {
|
.tab-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
//Prevent margin breakout of lis
|
//Prevent margin breakout of lis
|
||||||
|
@ -8,10 +11,9 @@
|
||||||
$color-2: #b7c3ce;
|
$color-2: #b7c3ce;
|
||||||
$hover-color: #9aa4ad;
|
$hover-color: #9aa4ad;
|
||||||
|
|
||||||
text-overflow: ellipsis;
|
display: flex;
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
padding: 5px 4px;
|
padding: 5px 4px;
|
||||||
|
white-space: nowrap;
|
||||||
background-color: $color-1;
|
background-color: $color-1;
|
||||||
|
|
||||||
&:nth-child(2n) {
|
&:nth-child(2n) {
|
||||||
|
@ -21,6 +23,11 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $hover-color;
|
background-color: $hover-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-title {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
tabs.getWindows((windows: chrome.windows.Window[]) => {
|
tabs.getWindows((windows: chrome.windows.Window[]) => {
|
||||||
document.querySelector("body").innerHTML = String(MAIN_TEMPLATE.render({windows}));
|
document.querySelector("body").innerHTML = String(MAIN_TEMPLATE.render({windows}));
|
||||||
registerTabClickListeners();
|
registerTabClickListeners();
|
||||||
|
registerCloseButtonClickListeners();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -28,3 +29,18 @@ function registerTabClickListeners(): void {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* registerCloseButtonClickListeners registers click listeners to close tabs.
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function registerCloseButtonClickListeners(): void {
|
||||||
|
let closeButtons = document.getElementsByClassName("close-button");
|
||||||
|
[].forEach.call(closeButtons, (element) => {
|
||||||
|
element.addEventListener("click", (event) => {
|
||||||
|
let tabID = parseInt(element.parentNode.getAttribute("tab-id"));
|
||||||
|
tabs.closeTab(tabID);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export {getWindows, switchTo};
|
import * as util from "./util";
|
||||||
|
|
||||||
let windowCache: chrome.windows.Window[] = [];
|
let windowCache: chrome.windows.Window[] = [];
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ let windowCache: chrome.windows.Window[] = [];
|
||||||
* @param {(windows: chrome.windows.Window[]) => void} callback
|
* @param {(windows: chrome.windows.Window[]) => void} callback
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function getWindows(callback: (windows: chrome.windows.Window[]) => void): void {
|
export function getWindows(callback: (windows: chrome.windows.Window[]) => void): void {
|
||||||
chrome.windows.getAll({populate: true}, (windows : chrome.windows.Window[]) => {
|
chrome.windows.getAll({populate: true}, (windows : chrome.windows.Window[]) => {
|
||||||
windowCache = windows;
|
windowCache = windows;
|
||||||
callback(windows);
|
callback(windows);
|
||||||
|
@ -20,10 +20,33 @@ function getWindows(callback: (windows: chrome.windows.Window[]) => void): void
|
||||||
*
|
*
|
||||||
* @param {number} windowID the tab in which the window is contained.
|
* @param {number} windowID the tab in which the window is contained.
|
||||||
* @param {number} tabID The tab to switch to.
|
* @param {number} tabID The tab to switch to.
|
||||||
* @returns {void}
|
* @returns {PromiseLike<chrome.tabs.Tab>}
|
||||||
*/
|
*/
|
||||||
function switchTo(windowID: number, tabID: number): void {
|
export function switchTo(windowID: number, tabID: number): PromiseLike<chrome.tabs.Tab> {
|
||||||
chrome.windows.update(windowID, {focused: true}, () => {
|
let curriedWindowUpdate = (windowID: number, options: object) => {
|
||||||
chrome.tabs.update(tabID, {active: true});
|
return (callback: ((win: chrome.windows.Window) => void)) => chrome.windows.update(windowID, options, callback);
|
||||||
});
|
};
|
||||||
|
let curriedTabUpdate = (tabID: number, options: object) => {
|
||||||
|
return (callback: (tab: chrome.tabs.Tab) => void) => chrome.tabs.update(tabID, options, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
return util.callbackToPromise(curriedWindowUpdate(windowID, {focused: true}))
|
||||||
|
.then((returns: chrome.windows.Window[]) => util.callbackToPromise(curriedTabUpdate(tabID, {active: true})))
|
||||||
|
.then((returns: chrome.tabs.Tab[]) => returns[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* closeTab closes a tab with the given id
|
||||||
|
*
|
||||||
|
* @param {number} tabID
|
||||||
|
* @param {() => void} callback
|
||||||
|
* @returns {PromiseLike<void>}
|
||||||
|
*/
|
||||||
|
export function closeTab(tabID: number, callback?: () => void): PromiseLike<void> {
|
||||||
|
let curriedRemoveTab = (tabID: number) => {
|
||||||
|
return (callback: () => void) => chrome.tabs.remove(tabID);
|
||||||
|
};
|
||||||
|
|
||||||
|
return util.callbackToPromise(curriedRemoveTab(tabID))
|
||||||
|
.then(() => {}); // Force a removal of the return type
|
||||||
}
|
}
|
||||||
|
|
14
src/ts/util.ts
Normal file
14
src/ts/util.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* callbackToPromise converts a callback based function to a promise based function.
|
||||||
|
* The function's only argument must be a function.
|
||||||
|
*
|
||||||
|
* @param {(Function) => void} func
|
||||||
|
* @returns {PromiseLike<any[]>}
|
||||||
|
*/
|
||||||
|
export function callbackToPromise(func: (Function) => void): PromiseLike<any[]> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
func((...callbackArgs) => {
|
||||||
|
resolve(callbackArgs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
<span class="tab-title">
|
<span class="tab-title">
|
||||||
{{ tab.title }}
|
{{ tab.title }}
|
||||||
</span>
|
</span>
|
||||||
|
<i class="close-button fas fa-times-circle"></i>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
Loading…
Reference in a new issue