Angular Kana
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.17/angular-ui-router.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<div ng-app="kana">
<script type="text/ng-template" id="page.html">
<nav>
<sub-link set="set" sub="gojuon" label="Gojūon"></sub-link>
<sub-link set="set" sub="gojuon_dakuten" label="Gojūon + Dakuten"></sub-link>
<sub-link set="set" sub="yoon" label="Yōon"></sub-link>
<sub-link set="set" sub="yoon_dakuten" label="Yōon + Dakuten"></sub-link>
<sub-link set="set" sub="test" label="Test"></sub-link>
</nav>
<div ui-view></div>
</script>
<script type="text/ng-template" id="table.html">
<div class="kana-table-wrapper">
<div class="kana-table clearfix">
<ul ng-repeat="col in chars">
<li ng-repeat="c in col">
<div class="spacing" ng-repeat="n in c.sp track by $index"></div>
<div class="kana" ng-class="{yoon: sub==='yoon'||sub==='yoon_dakuten'}">
<div class="jp" title="{{c.rom}}">{{c.jp}}</div>
<div class="rom">
<span ng-show="romaji">{{c.rom}}</span>
<span ng-show="!romaji"> </span>
</div>
</div>
</li>
</ul>
</div>
</div>
<footer>
<a class="btn" ng-click="romaji=!romaji">
<span ng-show="romaji">Hide Rōmaji</span>
<span ng-show="!romaji">Show Rōmaji</span>
</a>
</footer>
</script>
<script type="text/ng-template" id="test.html">
<div class="test">
<div class="kana" ng-class="{yoon: sub==='yoon'||sub==='yoon_dakuten'}">
<div class="jp">{{curr.jp}}</div>
</div>
<div>
<input type="text" ng-model="reply">
</div>
<div class="score">Score : {{score}}/{{total}}</div>
</div>
<footer>
<a class="btn" ng-click="check()">OK</a>
<a class="btn" ng-click="next()">Pass</a>
<a class="btn"...
SCSS
@import url(https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900);
@import url(https://fonts.googleapis.com/css?family=Oswald:300,400,700);
$color-bg-white: #fafafa;
$color-bg-lightgray: #eee;
$color-bg-gray: #ddd;
$color-bg-darkgray: #666;
$color-bg-dark: #333;
$color-bg-true: #4cae4c;
$color-bg-false: #d43f3a;
$color-font-white: #fff;
$color-font-black: #333;
$color-accent: steelblue;
$nav-height: 60px;
$nav-font-size: 1.4em;
$nav-font-weight: 300;
$nav-border-size: 4px;
$kana-size: 40px;
$kana-jp-font-size: 1.4em;
$kana-rom-font-size: 1em;
$kana-table-spacing: 10px;
$kana-table-height: (5*1.5*$kana-size)+(4*$kana-table-spacing);
$content-padding: 20px;
$content-height: $kana-table-height + 80px + 40px + $content-padding;
$body-width: (11*$kana-size)+(10*$kana-table-spacing)+(2*$content-padding);
$transition: .2s;
/* ---------- GLOBAL ---------- */
* { box-sizing: border-box; }
.clearfix:after {
content: '';
display: block;
clear: both;
}
/* ---------- BUTTONS ---------- */
a {
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
a.btn {
display: inline-block;
padding: 10px 15px;
color: $color-font-black;
background: $color-bg-gray;
font-family: 'Oswald', sans-serif;
font-size: 1.2em;
font-weight: 300;
text-decoration: none;
transition: all $transition;
}
a.btn.active,
a.btn:hover {
background: $color-accent;
color: $color-font-white;
}
/* ---------- BODY ---------- */
body {
width: $body-width;
margin: 20px auto;
line-height: 20px;
background: linear-gradient($color-bg-darkgray, $color-bg-dark) no-repeat;
background-color: $color-bg-dark;
color: $color-font-black;
font-family: 'Roboto', sans-serif;
}
/* ---------- MAIN ---------- */
#main {
background: $color-bg-lightgray;
box-shadow: 0 4px 6px rgba(0,0,0,.3);
}
/* ---------- NAV ---------- */
header nav {
background: $color-bg-dark;
font-family: 'Oswald',...
JavaScript
var app = angular.module('kana', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('page', { url: '/:set', controller: 'pageCtrl', templateUrl: 'page.html' })
.state('page.test', { url: '/test', controller: 'testCtrl', template: '<test chars="chars"></test>' })
.state('page.sub', { url: '/:sub', controller: 'tableCtrl', templateUrl: 'table.html' });
$urlRouterProvider.otherwise('/hiragana/gojuon');
});
app.service('kana', function() {
this.sp = function(n) {
return new Array(n);
};
this.hiragana = {
'gojuon': [
[{jp:'あ',rom:'a'}, {jp:'い',rom:'i'}, {jp:'う',rom:'u'}, {jp:'え',rom:'e'}, {jp:'お',rom:'o'}],
[{jp:'か',rom:'ka'}, {jp:'き',rom:'ki'}, {jp:'く',rom:'ku'}, {jp:'け',rom:'ke'}, {jp:'こ',rom:'ko'}],
[{jp:'さ',rom:'sa'}, {jp:'し',rom:'shi'}, {jp:'す',rom:'su'}, {jp:'せ',rom:'se'}, {jp:'そ',rom:'so'}],
[{jp:'た',rom:'ta'}, {jp:'ち',rom:'chi'}, {jp:'つ',rom:'tsu'}, {jp:'て',rom:'te'}, {jp:'と',rom:'to'}],
[{jp:'な',rom:'na'}, {jp:'に',rom:'ni'}, {jp:'ぬ',rom:'nu'}, {jp:'ね',rom:'ne'}, {jp:'の',rom:'no'}],
[{jp:'は',rom:'ha'}, {jp:'ひ',rom:'hi'}, {jp:'ふ',rom:'fu'}, {jp:'へ',rom:'he'}, {jp:'ほ',rom:'ho'}],
[{jp:'ま',rom:'ma'}, {jp:'み',rom:'mi'}, {jp:'む',rom:'mu'}, {jp:'め',rom:'me'}, {jp:'も',rom:'mo'}],
[{jp:'や',rom:'ya'}, {jp:'み',rom:'yu',sp:this.sp(1)}, {jp:'よ',rom:'yo',sp:this.sp(1)}],
[{jp:'ら',rom:'ra'}, {jp:'り',rom:'ri'}, {jp:'る',rom:'ru'}, {jp:'れ',rom:'re'}, {jp:'ろ',rom:'ro'}],
[{jp:'や',rom:'wa'}, {jp:'よ',rom:'wo',sp:this.sp(3)}],
[{jp:'ん',rom:'n',sp:this.sp(4)}]
],
'gojuon_dakuten': [
[{jp:'が',rom:'ga'}, {jp:'ぎ',rom:'gi'}, {jp:'ぐ',rom:'gu'}, {jp:'げ',rom:'ge'}, {jp:'ご',rom:'go'}],
[{jp:'ざ',rom:'za'}, {jp:'じ',rom:'ji'}, {jp:'ず',rom:'zu'}, {jp:'ぜ',rom:'ze'}, {jp:'ぞ',rom:'zo'}],
[{jp:'だ',rom:'da'}, {jp:'で',rom:'de',sp:this.sp(2)}, {jp:'ど',rom:'do'}],
[{jp:'ば',rom:'ba'}, {jp:'び',rom:'bi'}, ...