Skip to content

Keybindings for problem navigation #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"presets": [
["env", {
"targets": {
"browsers": ["last 2 versions"],
"uglify": true
}
}]
]
}
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[ ![Codeship Status for PracticeJavaScript/practicejavascript.com](https://app.codeship.com/projects/091c0e50-0a7c-0135-8b3c-6ed4d7e33e57/status?branch=master)](https://app.codeship.com/projects/214753)
[![Build Status](https://travis-ci.org/PracticeJavaScript/practicejavascript.com.svg?branch=master)](https://travis-ci.org/PracticeJavaScript/practicejavascript.com)

![ScreenShot of practicejavascript.com](https://cldup.com/9rdvK8A98t.png)
![ScreenShot of practicejavascript.com](https://cldup.com/cFITECDXpD.png)

## Principles
- Fast, easy to start. No delays.
Expand All @@ -29,9 +29,11 @@ firebase serve
```

- That will build it all and watch the css, img, and js assets.
- Then you can load up `http://localhost:5000` in a browser. narf!
- Then you can load up `http://localhost:5000` or `public/index.html` in a browser. narf!
`/src/index.js` is the main file you'll want to edit for functionality.
- If you have the [LiveReload Chrome extension](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei) installed, it should do live css updates in your browser while gulp watch is running
- CSS is auto-prefixed for the supported browserslist, so don't manually add any browser prefixes to CSS src.
- NOTE: If you change the UI, please update the screenshot at top of this README

## How To Add New Problems
- Problems are at `/src/problems/*.js`
Expand All @@ -54,3 +56,6 @@ Each test must have:
This test function will be run on code submission, and MUST return boolean. `output` param is available.
`output` is the output of the JavaScript evaluation of the user's code submission.
This test function may make chai.js assertions or any other comparison against the `output` value.

## Browser support
- See `browserslist` settings in package.json
40 changes: 27 additions & 13 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// DEPS
// ============================================================

const gulp = require('gulp');
const sourcemaps = require('gulp-sourcemaps');
const browserify = require('browserify');
Expand All @@ -6,30 +9,41 @@ const buffer = require('vinyl-buffer');
const uglify = require('gulp-uglify');
const watchify = require('watchify');
const babel = require('babelify');
const es2015 = require('babel-preset-es2015');
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const svgo = require('gulp-svgo');
const sass = require('gulp-sass');
const livereload = require('gulp-livereload');

function conf() {
const opts = {};
opts.builtins = false;
opts.entries = ['src/js/index.js'];
opts.debug = true;
opts.insertGlobalVars = {
// CONFIG
// ============================================================
const browserslist = require('./package.json').browserslist;

const opts = {
builtins: false,
entries: ['src/js/index.js'],
debug: true,
insertGlobalVars: {
global: glob
};
return opts;
}
}
};

const uglifyConf = {};

// TASKS
// ============================================================

function compile(watch) {
const opts = conf();
const bundler = watchify(browserify(opts).transform([babel, es2015]));
const bundler = watchify(browserify(opts).transform(babel.configure({
presets: [
['env', {
targets: {
browsers: browserslist
}
}]
]
})));
function rebundle() {
return bundler.bundle()
.on('error', err => {
Expand Down Expand Up @@ -64,7 +78,7 @@ function watch() {

gulp.task('css', () => {
const plugins = [
autoprefixer({browsers: ['last 1 version']}),
autoprefixer({browsers: browserslist}),
cssnano()
];
return gulp.src('./src/css/style.scss')
Expand Down
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@
"test": "xo",
"build": "./node_modules/.bin/gulp build",
"watch": "./node_modules/.bin/gulp watch",
"precommit": "lint-staged"
"precommit": "yarn test",
"prepush": "yarn test"
},
"browserslist": [
"> 1%",
"last 1 versions"
],
"xo": {
"env": [
"node",
Expand Down Expand Up @@ -43,7 +48,6 @@
"babelify": "^7.3.0",
"cssnano": "^3.10.0",
"gulp": "^3.9.1",
"gulp-bro": "^1.0.2",
"gulp-postcss": "^6.4.0",
"gulp-sourcemaps": "^2.5.1",
"gulp-uglify": "^2.1.2",
Expand All @@ -57,6 +61,7 @@
"xo": "^0.18.1"
},
"devDependencies": {
"babel-preset-env": "^1.4.0",
"babel-preset-es2017": "^6.24.1",
"babel-preset-latest": "^6.24.1",
"browserify": "^14.1.0",
Expand Down
2 changes: 1 addition & 1 deletion public/dist/css/style.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions public/dist/js/bundle.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/dist/js/bundle.min.js.map

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
<title>Practice JavaScript</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--<link rel="stylesheet" href="./dist/css/min.min.css">-->
<!--<link rel="stylesheet" href="https://cdn.jsdelivr.net/min/1.5/min.min.css">-->
<link href="./dist/css/style.css" rel="stylesheet">
</head>
<body>
Expand All @@ -17,15 +15,15 @@ <h1>Practice JavaScript!</h1>
</span>
<nav class="controls">
<div>
<img id="prev-problem" class="prev-problem" src="./dist/img/back.svg" alt="Previous problem" height="80">
<img id="prev-problem" class="prev-problem" src="./dist/img/back.svg" alt="Previous problem" title="Previous problem (CMD + SHIFT + RETURN or CTRL + SHIFT + ENTER)" height="80">
<div class="title">Back</div>
</div>
<div>
<img id="shuffle-problems" class="shuffle-problems" src="./dist/img/shuffle.svg" alt="Shuffle problems" title="Shuffle problems" height="80">
<div class="title">Shuffle</div>
</div>
<div>
<img id="next-problem" class="next-problem" src="./dist/img/next.svg" alt="Next problem" title="Next problem"height="80">
<img id="next-problem" class="next-problem" src="./dist/img/next.svg" alt="Next problem" title="Next problem (CMD + RETURN or CTRL + ENTER)" height="80">
<div class="title">Next</div>
</div>
</nav>
Expand Down
34 changes: 17 additions & 17 deletions src/css/lib/vars.scss
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
$persian-indigo: #2A0965;
$medium-purple: #8D6BE8;
$blue-gem: #492A9F;
$light-blue-gem: lighten($blue-gem, 20%);
$pinkish: #EB86BF;
$amethyst: #A456D1;
$light-amethyst: lighten($amethyst, 10%);
$light-purple: lighten($medium-purple, 20%);
$deep-lilac: #9D53B5;
// $persian-indigo: #2A0965;
// $medium-purple: #8D6BE8;
// $blue-gem: #492A9F;
// $light-blue-gem: lighten($blue-gem, 20%);
// $pinkish: #EB86BF;
// $amethyst: #A456D1;
// $light-amethyst: lighten($amethyst, 10%);
// $light-purple: lighten($medium-purple, 20%);
// $deep-lilac: #9D53B5;

/* Palette generated by Material Palette - materialpalette.com/deep-purple/pink */
$primary-color-dark: #512DA8;
$primary-color: #673AB7;
$primary-color-light: #D1C4E9;
$primary-color-text: #FFFFFF;
$accent-color: #FF4081;
$primary-text-color: #212121;
$secondary-text-color: #757575;
$divider-color: #BDBDBD;
// $primary-color-dark: #512DA8;
// $primary-color: #673AB7;
// $primary-color-light: #D1C4E9;
// $primary-color-text: #FFFFFF;
// $accent-color: #FF4081;
// $primary-text-color: #212121;
// $secondary-text-color: #757575;
// $divider-color: #BDBDBD;

// $primary-color-dark: #303F9F;
// $primary-color: #3F51B5;
Expand Down
9 changes: 8 additions & 1 deletion src/css/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
display: flex;
align-items: center;
justify-content: center;
text-shadow: 0 0 10px rgba(255,255,255,1),
// 0 0 20px rgba(255,255,255,1),
// 0 0 30px rgba(255,255,255,1),
0 0 40px $primary-color;
// 0 0 70px $primary-color;
// 0 0 80px $primary-color,
// 0 0 100px $primary-color;
}
.site-heading h1 {
font-size: 200%;
Expand All @@ -49,7 +56,7 @@
.controls > div > :active,
.controls > div > .active {
background-color: $primary-color;
transition: all 200ms ease-in-out;
transition: color 100ms ease-in-out;
}
.problem-group {
display: block;
Expand Down
34 changes: 30 additions & 4 deletions src/js/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
(function (document, window) {
// DEPENDENCIES
// ============================================================

const localforage = require('localforage');

// PROBLEMS
// ============================================================

const problems = require('../problems/arrays.js');

// CONFIG
// ============================================================

// Hoist current problem
let currentProblem;

// Keys to ignore while user is navigating around the textarea but not changing any code
const ignoreKeyCodes = [
9, // Tab
Expand Down Expand Up @@ -131,6 +130,8 @@

function previousProblem() {
console.log('previousProblem!');
// Activate back button, for visual queue of nav feedback
previousProblemButtonEl.classList.add('active');
config.currentIndex = config.shuffle
? getRandomIndex(problems)
: getPreviousIndex(problems);
Expand All @@ -141,6 +142,8 @@

function nextProblem() {
console.log('nextProblem!');
// Activate next button, for visual queue of nav feedback
nextProblemButtonEl.classList.add('active');
config.currentIndex = config.shuffle
? getRandomIndex(problems)
: getNextIndex(problems);
Expand Down Expand Up @@ -169,6 +172,7 @@
testSuite(null, true);
}

// TODO: Build the assert errors into the test dom on each update.
function updateTests(testStatus, init) {
if (init === true) {
buildTests(currentProblem.tests);
Expand Down Expand Up @@ -201,7 +205,7 @@
allPassed = false;
}
});
const testEls = Array.from(testSuiteEl.querySelectorAll('.test-state'));
const testEls = [].slice.call(testSuiteEl.querySelectorAll('.test-state'));
testEls.forEach((testStatusEl, iter) => {
if (testStatuses[iter] === true) {
testStatusEl.innerHTML = '[&#x2713;]';
Expand Down Expand Up @@ -312,6 +316,10 @@
previousProblemButtonEl.parentNode.classList.add('hidden');
}

// Keybinding stuff
// ============================================================

// Debounced code validation
const debouncedInputValidation = debounce(e => {
// If not arrow keys or other non-character keys
if (ignoreKeyCodes.indexOf(e.keyCode) === -1) {
Expand All @@ -320,8 +328,26 @@
}
}, 200);

function problemNav(e) {
// Go to previous problem keybinding
// If CMD/CTRL + SHIFT + RETURN/ENTER
if (config.shuffle === false && e.keyCode === 13 && e.shiftKey && (e.metaKey || e.ctrlKey)) {
// Go to next problem
previousProblem();
} else if (e.keyCode === 13 && !e.shiftKey && (e.metaKey || e.ctrlKey)) {
// Go to next problem keybinding
// If CMD/CTRL + RETURN/ENTER
// Go to next problem
nextProblem();
}
}

// Event Bindings
// ============================================================

// Bind it up
codeEl.addEventListener('keyup', debouncedInputValidation);
codeEl.addEventListener('keydown', debouncedInputValidation);
document.addEventListener('keydown', problemNav);
shuffleProblemsButtonEl.addEventListener('click', toggleShuffle);
previousProblemButtonEl.addEventListener('click', previousProblem);
nextProblemButtonEl.addEventListener('click', nextProblem);
Expand Down
Loading