JSFiddle - React, Tailwind, and code Playground
by Marc Malignan
HTML
<div id="scrabble" ng-app="scrabble" ng-controller="scrabbleCtrl">
<center>
<button id="draw" ng-click="draw()">Draw</button>
<button id="draw" ng-click="nextTurn()">Next turn</button>
</center>
<div><b>Turn :</b> Player {{turn}}</div>
<div><b>Score :</b> {{players[0].score}} pts</div>
<hand id="p2" class="clearfix" ng-class="{myturn: (turn==1)}">
<tile data="t" draggable="{{(turn==t.owner)}}"
ng-class="{draggable: (turn==t.owner)}"
ng-repeat="t in players[1].hand track by $index"></tile>
</hand>
<div id="board" class="clearfix">
<cell id="{{cellId($index+1)}}" ng-repeat="c in cells() track by $index" ></cell>
</div>
<hand id="p1" class="clearfix" ng-class="{myturn: (turn==0)}">
<tile data="t" draggable="{{(turn==t.owner)}}"
ng-class="{draggable: (turn==t.owner)}"
ng-repeat="t in players[0].hand track by $index"></tile>
</hand>
</div>
SCSS
$cell: 20px;
$border: $cell/10;
$bg: #f1ebd5;
$board: #efe9d3;
$red: #ec3330;
$pink: pink;
$blue: #1190d3;
$lightblue: #96cee9;
body {
background: $bg;
font-family: Arial;
}
center {
margin-bottom: 10px;
}
.clearfix:after {
content: '';
display: block;
clear: both;
}
#scrabble {
cursor: default;
}
#board {
margin: 0 auto;
padding: $border 0 0 $border;
width: (15*$cell)+(15*$border);
background: white;
border-radius: $cell/10;
box-shadow: 0 2px 8px rgba(0,0,0,.3);
}
cell, tile {
display: block;
position: relative;
width: $cell;
height: $cell;
line-height: $cell;
text-align: center;
border-radius: $cell/20;
}
cell {
float: left;
margin: 0 $border $border 0;
background: $board;
}
tile {
background: #eee;
cursor: no-drop;
}
tile.draggable { cursor: -webkit-grab; }
tile.draggable:active { cursor: -webkit-grabbing; }
tile .pts {
position: absolute;
top: 0; right: 0;
line-height: $cell/3;
font-size: 40%;
}
hand {
display: block;
margin: 20px auto;
padding: $border 0 $border $border;
width: ($cell*15) + ($border*15);
background: #333;
border-radius: $cell/10;
}
hand tile {
float: left;
margin-right: $border;
}
hand.myturn {
box-shadow: 0 0 0 2px limegreen;
}
#h8:before {
content: '\2605';
position: absolute;
top: 0; left: 0; right: 0;
line-height: $cell;
font-size: $cell;
text-align: center;
}
#a4, #a12,
#c7, #c9,
#d1, #d8, #d15,
#g3, #g7, #g9, #g13,
#h4, #h12,
#i3, #i7, #i9, #i13,
#l1, #l8, #l15,
#m7, #m9,
#o4, #o12 { background: $lightblue; }
#b6, #b10,
#f2, #f6, #f10, #f14,
#j2, #j6, #j10, #j14,
#n6, #n10 { background: $blue; }
#b2, #c3, #d4, #e5,
#b14, #c13, #d12, #e11,
#h8,
#n2, #m3, #l4, #k5,
#n14, #m13, #l12, #k11,{ background: pink; }
#a1, #a8, #a15,
#h1, #h15,
#o1, #o8, #o15 { background: $red }
JavaScript
var app = angular.module('scrabble', []);
app.directive('cell', function($rootScope) {
return {
restrict: 'E',
link: function(scope, el, attrs, controller) {
scope.tile = null;
el.bind("dragover", function(e) {
e.preventDefault();
return false;
});
el.bind("drop", function(e) {
e.preventDefault();
scope.tile = $rootScope.dragged;
$rootScope.word[el.attr('id')] = scope.tile;
$rootScope.$broadcast("dropBoard", scope.tile);
});
},
template: '<tile data="tile" ng-if="tile" draggable="{{(turn==tile.owner)}}" ng-class="{draggable: (turn==tile.owner)}"></tile>'
}
});
app.directive('hand', function($rootScope) {
return {
restrict: 'E',
link: function(scope, el, attrs, controller) {
el.bind("dragover", function(e) {
if('p'+($rootScope.turn+1) == el.attr('id')) {
e.preventDefault();
return false;
}
});
el.bind("drop", function(e) {
e.preventDefault();
$rootScope.$broadcast("dropHand", $rootScope.dragged);
});
}
}
});
app.directive('tile', function($rootScope) {
return {
restrict: 'E',
scope: { data: '=' },
link: function(scope, el, attrs, controller) {
el.bind("dragstart", function(e) {
var parent = el.parent();
parent.scope().tile = null;
delete $rootScope.word[parent.attr('id')];
$rootScope.$broadcast("dragStart", scope.data);
});
el.bind("dragend", function(e) {
e.preventDefault();
$rootScope.$broadcast("dragEnd");
});
},
...