Browse Source

user edit form

pull/26/head
Ondřej Hruška 4 years ago
parent
commit
1c6dedbb34
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 10
      app/Http/Controllers/Auth/RegisterController.php
  2. 28
      app/Http/Controllers/Controller.php
  3. 43
      app/Http/Controllers/TableController.php
  4. 61
      app/Http/Controllers/UserController.php
  5. 1
      app/Models/EmailConfirmation.php
  6. 3
      app/Models/User.php
  7. 29
      app/Providers/ValidationServiceProvider.php
  8. 2
      app/View/Widget.php
  9. 42
      app/helpers.php
  10. 1
      composer.json
  11. 56
      composer.lock
  12. 1
      config/app.php
  13. 1
      database/migrations/2018_07_22_083900_create_email_confirmations_table.php
  14. 51
      porklib/helpers.php
  15. 213
      public/fonts/fa-dtbl-1-preview.html
  16. 85
      public/fonts/fa-dtbl-1.css
  17. BIN
      public/fonts/fa-dtbl-1.eot
  18. 102
      public/fonts/fa-dtbl-1.svg
  19. BIN
      public/fonts/fa-dtbl-1.ttf
  20. BIN
      public/fonts/fa-dtbl-1.woff2
  21. 20
      resources/assets/js/app.js
  22. 9
      resources/assets/sass/app.scss
  23. 10
      resources/views/form/input.blade.php
  24. 5
      resources/views/layouts/app.blade.php
  25. 102
      resources/views/table/create.blade.php
  26. 54
      resources/views/table/view.blade.php
  27. 61
      resources/views/user/edit.blade.php
  28. 129
      resources/views/user/view.blade.php
  29. 14
      resources/views/welcome.blade.php

10
app/Http/Controllers/Auth/RegisterController.php

@ -49,16 +49,14 @@ class RegisterController extends Controller
*/
protected function validator(array $data)
{
return Validator::make($data, [
return $this->makeValidator($data, [
'name' => [
'regex:/^[a-zA-Z0-9_.-]+$/',
'required',
'string',
'max:255',
VALI_NAME,
'unique:users'
],
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|max:1000|confirmed', // max len to foil DOS attempts
'email' => ['required', 'unique:users', VALI_EMAIL],
'password' => ['required', 'confirmed', VALI_PASSWORD],
]);
}

28
app/Http/Controllers/Controller.php

@ -3,13 +3,39 @@
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
use AuthorizesRequests,
DispatchesJobs,
ValidatesRequests {
ValidatesRequests::validate as validate_orig;
ValidatesRequests::validateWithBag as validateWithBag_orig;
}
// Hacks to allow recursive nesting of validations in string and array format
public function makeValidator($data, $rules, $messages = array(), $customAttributes = array())
{
return \Validator::make($data, vali($rules), $messages, $customAttributes);
}
public function validate(Request $request, array $rules,
array $messages = [], array $customAttributes = [])
{
return objBag($this->validate_orig($request, vali($rules), $messages, $customAttributes));
}
public function validateWithBag($errorBag, Request $request, array $rules,
array $messages = [], array $customAttributes = [])
{
return objBag($this->validateWithBag_orig($errorBag, $request, vali($rules),
$messages, $customAttributes));
}
protected function backWithErrors($errors)
{

43
app/Http/Controllers/TableController.php

@ -54,21 +54,24 @@ class TableController extends Controller
/** @var User $u */
$u = \Auth::user();
$this->validate($request, [
'name' => 'required|string|max:255',
'title' => 'string|string|max:255',
'description' => 'string|nullable|max:4000',
'license' => 'string|nullable|max:4000',
'origin' => 'string|nullable|max:4000',
$input = $this->validate($request, [
'name' => [
'required',
VALI_NAME,
Rule::unique('tables'),
],
'title' => ['required', VALI_LINE],
'description' => ['nullable', VALI_TEXT],
'license' => ['nullable', VALI_TEXT],
'origin' => ['nullable', VALI_TEXT],
'columns' => 'required|string',
'data' => 'string|nullable',
]);
// Check if table name is unique for user
$tabName = $request->get('name');
if ($u->tables()->where('name', $tabName)->exists()) {
if ($u->tables()->where('name', $input->name)->exists()) {
return $this->backWithErrors([
'name' => "A table called \"$tabName\" already exists in your account.",
'name' => "A table called \"$input->name\" already exists in your account.",
]);
}
@ -76,7 +79,7 @@ class TableController extends Controller
/** @var Column[] $columns */
$columns = [];
$column_keys = []; // for checking duplicates
$colTable = array_map('str_getcsv', explode("\n", $request->get('columns')));
$colTable = array_map('str_getcsv', explode("\n", $input->columns));
// prevent griefing via long list of columns
if (count($colTable) > 100) return $this->backWithErrors(['columns' => "Too many columns"]);
@ -104,7 +107,7 @@ class TableController extends Controller
}
if (count($columns) == 0) return $this->backWithErrors(['columns' => "Define at least one column"]);
$rowTable = array_map('str_getcsv', explode("\n", $request->get('data')));
$rowTable = array_map('str_getcsv', explode("\n", $input->data));
// Preparing data to insert into the Rows table
$rowsData = null;
@ -116,6 +119,10 @@ class TableController extends Controller
$parsed = [];
foreach ($row as $i => $val) {
$key = $columns[$i]->name;
if (strlen($val) > 255) {
// try to stop people inserting unstructured crap / malformed CSV
throw new NotApplicableException("Value for column $key too long.");
}
$parsed[$key] = $columns[$i]->cast($val);
}
return [
@ -127,7 +134,7 @@ class TableController extends Controller
}
$revisionFields = [
'note' => "Initial revision of table $u->name/$tabName",
'note' => "Initial revision of table $u->name/$input->name",
'columns' => json_encode($columns),
'row_count' => count($rowsData),
];
@ -135,11 +142,11 @@ class TableController extends Controller
$tableFields = [
'owner_id' => $u->id,
'revision_id' => 0,
'name' => $tabName,
'title' => $request->get('title'),
'description' => $request->get('description'),
'license' => $request->get('license'),
'origin' => $request->get('origin'),
'name' => $input->name,
'title' => $input->title,
'description' => $input->description,
'license' => $input->license,
'origin' => $input->origin,
];
\DB::transaction(function () use ($revisionFields, $tableFields, $rowsData) {
@ -156,6 +163,6 @@ class TableController extends Controller
$revision->rows()->createMany($rowsData);
});
return redirect(route('table.view', ['user' => $u, 'table' => $tabName]));
return redirect(route('table.view', ['user' => $u, 'table' => $input->name]));
}
}

61
app/Http/Controllers/UserController.php

@ -3,7 +3,12 @@
namespace App\Http\Controllers;
use App\Models\EmailConfirmation;
use App\Models\User;
use Hash;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use MightyPork\Utils\Str;
class UserController extends Controller
{
@ -22,18 +27,66 @@ class UserController extends Controller
}
/**
* Edit user profile
* Edit own profile
*
* @param User $user
* @return \Illuminate\View\View
*/
public function edit()
{
return view('user.edit')->with('user', \Auth::user());
return view('user.edit')->with('user', \user());
}
public function store()
/**
* Store changed profile
*/
public function store(Request $request)
{
echo "Not impl";
$input = $this->validate($request, [
'name' => [
'required',
VALI_NAME,
Rule::unique('users')->ignoreModel(\user()),
],
'email' => [
'required',
VALI_EMAIL,
Rule::unique('users')->ignoreModel(\user()),
],
'bio' => ['nullable', VALI_TEXT],
'title' => ['required', VALI_LINE],
'website' => ['required', VALI_LINE],
'new_password' => ['nullable', 'confirmed', VALI_PASSWORD],
]);
$user = user();
if ($input->email != $user->email) {
$confirmation = EmailConfirmation::create([
'user_id' => $user->id,
'email' => $input->email,
'token' => Str::random(60),
]);
flash()->warning("New e-mail confirmation sent to $input->email.")->important();
// TODO send the e-mail
unset($input->email);
}
$user->fill($input->all());
if ($input->has('new_password')) {
$user->password = Hash::make($input->new_password);
flash()->warning('Password changed');
}
$user->save();
flash()->success('Settings saved');
return back();
}
}

1
app/Models/EmailConfirmation.php

@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\Model;
* @property \Carbon\Carbon $created_at
* @property int $user_id
* @property string $token
* @property string $email
* @property-read User $user
*/
class EmailConfirmation extends Model

3
app/Models/User.php

@ -21,6 +21,7 @@ use MightyPork\Exceptions\NotExistException;
* @property string $name - unique, for vanity URL
* @property string $title - for display
* @property string $bio - user bio
* @property string $website - custom url
* @property string $email - unique, for login and social auth chaining
* @property string $password - hashed pw
* @property bool $confirmed - user e-mail is confirmed
@ -48,7 +49,7 @@ class User extends Authenticatable
* @var array
*/
protected $fillable = [
'name', 'title', 'email', 'password',
'name', 'title', 'email', 'password', 'bio', 'website'
];
/**

29
app/Providers/ValidationServiceProvider.php

@ -0,0 +1,29 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Validator;
class ValidationServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register services.
*
* @return void
*/
public function register()
{
//
}
}

2
app/View/Widget.php

@ -9,6 +9,8 @@ namespace App\View;
* @property-read string $name
* @property-read string $id
* @property-read string $label
* @property-read string $prepend
* @property-read string $append
* @property-read string|null $help
* @property-read string|null $value
* @property-read string $attributes

42
app/helpers.php

@ -1,5 +1,11 @@
<?php
const VALI_NAME = 'string|regex:/^[a-z0-9_.-]+$/i|max:255';
const VALI_PASSWORD = 'string|min:6|max:1024';
const VALI_EMAIL = 'string|email|max:255';
const VALI_TEXT = 'string|max:4095';
const VALI_LINE = 'string|max:255';
// global helpers
function authed() {
return ! \Auth::guest();
@ -22,3 +28,39 @@ function faker() {
if ($fac !== null) return $fac;
return $fac = Faker\Factory::create();
}
/**
* Recursively expand validation rules
*
* @param $arr
* @return array
*/
function vali($arr) {
$result = [];
foreach ($arr as $key => $rules) {
// top level
if (is_array($rules)) {
$ar = [];
foreach ($rules as $rule) {
if (is_string($rule) && strpos($rule, '|') !== false) {
foreach (explode('|', $rule) as $rr) {
$ar[] = $rr;
}
} else if (is_array($rule)) {
// nested array, assume no further recursion
foreach ($rule as $rr) {
$ar[] = $rr;
}
} else {
// Rule
$ar[] = $rule;
}
}
$result[$key] = $ar;
} else {
// string or Rule
$result[$key] = $rules;
}
}
return $result;
}

1
composer.json

@ -14,6 +14,7 @@
"doctrine/dbal": "^2.7",
"fideloper/proxy": "^4.0",
"guzzlehttp/guzzle": "^6.0",
"laracasts/flash": "^3.0",
"laravel/framework": "5.6.*",
"laravel/socialite": "^3.0",
"laravel/tinker": "^1.0",

56
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "1bb552d1b383427434286ed0ced8293b",
"content-hash": "4a71a6ea4e0158136c11e0a93170b0c3",
"packages": [
{
"name": "barryvdh/laravel-debugbar",
@ -1051,6 +1051,60 @@
],
"time": "2015-04-20T18:58:01+00:00"
},
{
"name": "laracasts/flash",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/laracasts/flash.git",
"reference": "10cd420ab63fd0796bf5e1e5b99f87636d2f4333"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laracasts/flash/zipball/10cd420ab63fd0796bf5e1e5b99f87636d2f4333",
"reference": "10cd420ab63fd0796bf5e1e5b99f87636d2f4333",
"shasum": ""
},
"require": {
"illuminate/support": "~5.0",
"php": ">=5.4.0"
},
"require-dev": {
"mockery/mockery": "dev-master",
"phpunit/phpunit": "^6.1"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laracasts\\Flash\\FlashServiceProvider"
],
"aliases": {
"Flash": "Laracasts\\Flash\\Flash"
}
}
},
"autoload": {
"psr-0": {
"Laracasts\\Flash": "src/"
},
"files": [
"src/Laracasts/Flash/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jeffrey Way",
"email": "jeffrey@laracasts.com"
}
],
"description": "Easy flash notifications",
"time": "2017-06-22T19:01:19+00:00"
},
{
"name": "laravel/framework",
"version": "v5.6.27",

1
config/app.php

@ -159,6 +159,7 @@ return [
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\ValidationServiceProvider::class,
MightyPork\Providers\BladeExtensionsProvider::class,
MightyPork\Providers\MacroServiceProvider::class,

1
database/migrations/2018_07_22_083900_create_email_confirmations_table.php

@ -14,6 +14,7 @@ class CreateEmailConfirmationsTable extends Migration
public function up()
{
Schema::create('email_confirmations', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id')->index();
$table->timestamp('created_at')->nullable();
$table->string('email');

51
porklib/helpers.php

@ -65,7 +65,8 @@ function unless($cond, $then, $else = '')
* - Undefined keys are returned as null.
* - array and object values are wrapped in objBag when returned.
*/
class objBag implements JsonSerializable {
class objBag implements JsonSerializable, ArrayAccess {
/** @var object */
private $wrapped;
public function __construct($wrapped)
@ -86,7 +87,21 @@ class objBag implements JsonSerializable {
return null;
}
public function __isset($name)
public function __set($name, $value)
{
if ($this->wrapped) {
$this->wrapped->$name = $value;
}
}
public function __unset($name)
{
if ($this->wrapped) {
unset($this->wrapped->$name);
}
}
public function __isset($name)
{
return isset($this->wrapped->$name);
}
@ -99,7 +114,7 @@ class objBag implements JsonSerializable {
public function has($name)
{
return isset($this->$name);
return isset($this->$name) && $this->$name !== null;
}
public function unpack()
@ -107,6 +122,16 @@ class objBag implements JsonSerializable {
return $this->wrapped;
}
public function toArray()
{
return(array)$this->wrapped;
}
public function all()
{
return $this->toArray();
}
/**
* Specify data which should be serialized to JSON
*
@ -119,6 +144,26 @@ class objBag implements JsonSerializable {
{
return $this->wrapped;
}
public function offsetExists($offset)
{
return isset($this->$offset);
}
public function offsetGet($offset)
{
return $this->$offset;
}
public function offsetSet($offset, $value)
{
$this->$offset = $value;
}
public function offsetUnset($offset)
{
unset($this->$offset);
}
}
function objBag($obj) {

213
public/fonts/fa-dtbl-1-preview.html

@ -161,7 +161,8 @@
[data-icon]:before { content: attr(data-icon); }
[data-icon]:before,
.fa-bell:before,
.fa-at:before,
.fa-bell:before,
.fa-bell-o:before,
.fa-calendar:before,
.fa-check:before,
@ -177,8 +178,10 @@
.fa-floppy-o:before,
.fa-gavel:before,
.fa-github:before,
.fa-globe:before,
.fa-google:before,
.fa-history:before,
.fa-key-modern:before,
.fa-link:before,
.fa-pencil-square-o:before,
.fa-question-circle:before,
@ -216,47 +219,50 @@
font-smoothing: antialiased;
}
.fa-bell:before { content: "\f100"; }
.fa-bell-o:before { content: "\f101"; }
.fa-calendar:before { content: "\f102"; }
.fa-check:before { content: "\f103"; }
.fa-clock-o:before { content: "\f104"; }
.fa-cloud-upload:before { content: "\f105"; }
.fa-code-fork:before { content: "\f106"; }
.fa-download:before { content: "\f107"; }
.fa-eye:before { content: "\f108"; }
.fa-eye-slash:before { content: "\f109"; }
.fa-facebook-square:before { content: "\f10a"; }
.fa-filter:before { content: "\f10b"; }
.fa-flag:before { content: "\f10c"; }
.fa-floppy-o:before { content: "\f10d"; }
.fa-gavel:before { content: "\f10e"; }
.fa-github:before { content: "\f10f"; }
.fa-google:before { content: "\f110"; }
.fa-history:before { content: "\f111"; }
.fa-link:before { content: "\f112"; }
.fa-pencil-square-o:before { content: "\f113"; }
.fa-question-circle:before { content: "\f114"; }
.fa-quote-left:before { content: "\f115"; }
.fa-reply:before { content: "\f116"; }
.fa-rss:before { content: "\f117"; }
.fa-search:before { content: "\f118"; }
.fa-share-alt:before { content: "\f119"; }
.fa-sign-in:before { content: "\f11a"; }
.fa-sign-out:before { content: "\f11b"; }
.fa-sliders:before { content: "\f11c"; }
.fa-sort:before { content: "\f11d"; }
.fa-sort-asc:before { content: "\f11e"; }
.fa-sort-desc:before { content: "\f11f"; }
.fa-star:before { content: "\f120"; }
.fa-star-o:before { content: "\f121"; }
.fa-table:before { content: "\f122"; }
.fa-times:before { content: "\f123"; }
.fa-trash:before { content: "\f124"; }
.fa-trash-o:before { content: "\f125"; }
.fa-user-circle-o:before { content: "\f126"; }
.fa-user-plus:before { content: "\f127"; }
.fa-wrench:before { content: "\f128"; }
.fa-at:before { content: "\f100"; }
.fa-bell:before { content: "\f101"; }
.fa-bell-o:before { content: "\f102"; }
.fa-calendar:before { content: "\f103"; }
.fa-check:before { content: "\f104"; }
.fa-clock-o:before { content: "\f105"; }
.fa-cloud-upload:before { content: "\f106"; }
.fa-code-fork:before { content: "\f107"; }
.fa-download:before { content: "\f108"; }
.fa-eye:before { content: "\f109"; }
.fa-eye-slash:before { content: "\f10a"; }
.fa-facebook-square:before { content: "\f10b"; }
.fa-filter:before { content: "\f10c"; }
.fa-flag:before { content: "\f10d"; }
.fa-floppy-o:before { content: "\f10e"; }
.fa-gavel:before { content: "\f10f"; }
.fa-github:before { content: "\f110"; }
.fa-globe:before { content: "\f111"; }
.fa-google:before { content: "\f112"; }
.fa-history:before { content: "\f113"; }
.fa-key-modern:before { content: "\f114"; }
.fa-link:before { content: "\f115"; }
.fa-pencil-square-o:before { content: "\f116"; }
.fa-question-circle:before { content: "\f117"; }
.fa-quote-left:before { content: "\f118"; }
.fa-reply:before { content: "\f119"; }
.fa-rss:before { content: "\f11a"; }
.fa-search:before { content: "\f11b"; }
.fa-share-alt:before { content: "\f11c"; }
.fa-sign-in:before { content: "\f11d"; }
.fa-sign-out:before { content: "\f11e"; }
.fa-sliders:before { content: "\f11f"; }
.fa-sort:before { content: "\f120"; }
.fa-sort-asc:before { content: "\f121"; }
.fa-sort-desc:before { content: "\f122"; }
.fa-star:before { content: "\f123"; }
.fa-star-o:before { content: "\f124"; }
.fa-table:before { content: "\f125"; }
.fa-times:before { content: "\f126"; }
.fa-trash:before { content: "\f127"; }
.fa-trash-o:before { content: "\f128"; }
.fa-user-circle-o:before { content: "\f129"; }
.fa-user-plus:before { content: "\f12a"; }
.fa-wrench:before { content: "\f12b"; }
</style>
<!--[if lte IE 8]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
@ -272,11 +278,24 @@
<body class="characters-off">
<div id="page" class="container">
<header>
<h1>fa-dtbl-1 contains 41 glyphs:</h1>
<h1>fa-dtbl-1 contains 44 glyphs:</h1>
<a onclick="toggleCharacters(); return false;" href="#">Toggle Preview Characters</a>
</header>
<div class="glyph">
<div class="preview-glyphs">
<span class="step size-12"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-14"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-16"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-18"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-21"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-24"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-36"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-48"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-60"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span><span class="step size-72"><span class="letters">Pp</span><i id="fa-at" class="fa-at"></i></span>
</div>
<div class="preview-scale">
<span class="step">12</span><span class="step">14</span><span class="step">16</span><span class="step">18</span><span class="step">21</span><span class="step">24</span><span class="step">36</span><span class="step">48</span><span class="step">60</span><span class="step">72</span>
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-at" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf100;" />
</div>
</div>
<div class="glyph">
<div class="preview-glyphs">
<span class="step size-12"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-14"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-16"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-18"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-21"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-24"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-36"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-48"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-60"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span><span class="step size-72"><span class="letters">Pp</span><i id="fa-bell" class="fa-bell"></i></span>
@ -286,7 +305,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-bell" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf100;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf101;" />
</div>
</div>
@ -299,7 +318,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-bell-o" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf101;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf102;" />
</div>
</div>
@ -312,7 +331,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-calendar" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf102;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf103;" />
</div>
</div>
@ -325,7 +344,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-check" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf103;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf104;" />
</div>
</div>
@ -338,7 +357,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-clock-o" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf104;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf105;" />
</div>
</div>
@ -351,7 +370,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-cloud-upload" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf105;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf106;" />
</div>
</div>
@ -364,7 +383,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-code-fork" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf106;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf107;" />
</div>
</div>
@ -377,7 +396,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-download" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf107;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf108;" />
</div>
</div>
@ -390,7 +409,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-eye" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf108;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf109;" />
</div>
</div>
@ -403,7 +422,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-eye-slash" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf109;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10a;" />
</div>
</div>
@ -416,7 +435,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-facebook-square" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10a;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10b;" />
</div>
</div>
@ -429,7 +448,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-filter" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10b;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10c;" />
</div>
</div>
@ -442,7 +461,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-flag" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10c;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10d;" />
</div>
</div>
@ -456,7 +475,7 @@
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-floppy-o" />
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-save" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10d;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10e;" />
</div>
</div>
@ -470,7 +489,7 @@
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-gavel" />
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-legal" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10e;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10f;" />
</div>
</div>
@ -483,7 +502,20 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-github" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf10f;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf110;" />
</div>
</div>
<div class="glyph">
<div class="preview-glyphs">
<span class="step size-12"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-14"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-16"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-18"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-21"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-24"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-36"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-48"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-60"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span><span class="step size-72"><span class="letters">Pp</span><i id="fa-globe" class="fa-globe"></i></span>
</div>
<div class="preview-scale">
<span class="step">12</span><span class="step">14</span><span class="step">16</span><span class="step">18</span><span class="step">21</span><span class="step">24</span><span class="step">36</span><span class="step">48</span><span class="step">60</span><span class="step">72</span>
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-globe" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf111;" />
</div>
</div>
@ -496,7 +528,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-google" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf110;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf112;" />
</div>
</div>
@ -509,7 +541,20 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-history" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf111;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf113;" />
</div>
</div>
<div class="glyph">
<div class="preview-glyphs">
<span class="step size-12"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-14"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-16"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-18"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-21"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-24"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-36"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-48"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-60"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span><span class="step size-72"><span class="letters">Pp</span><i id="fa-key-modern" class="fa-key-modern"></i></span>
</div>
<div class="preview-scale">
<span class="step">12</span><span class="step">14</span><span class="step">16</span><span class="step">18</span><span class="step">21</span><span class="step">24</span><span class="step">36</span><span class="step">48</span><span class="step">60</span><span class="step">72</span>
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-key-modern" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf114;" />
</div>
</div>
@ -522,7 +567,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-link" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf112;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf115;" />
</div>
</div>
@ -536,7 +581,7 @@
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-pencil-square-o" />
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-edit" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf113;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf116;" />
</div>
</div>
@ -549,7 +594,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-question-circle" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf114;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf117;" />
</div>
</div>
@ -562,7 +607,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-quote-left" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf115;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf118;" />
</div>
</div>
@ -575,7 +620,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-reply" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf116;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf119;" />
</div>
</div>
@ -588,7 +633,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-rss" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf117;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11a;" />
</div>
</div>
@ -601,7 +646,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-search" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf118;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11b;" />
</div>
</div>
@ -614,7 +659,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-share-alt" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf119;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11c;" />
</div>
</div>
@ -627,7 +672,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-sign-in" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11a;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11d;" />
</div>
</div>
@ -640,7 +685,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-sign-out" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11b;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11e;" />
</div>
</div>
@ -653,7 +698,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-sliders" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11c;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11f;" />
</div>
</div>
@ -666,7 +711,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-sort" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11d;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf120;" />
</div>
</div>
@ -679,7 +724,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-sort-asc" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11e;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf121;" />
</div>
</div>
@ -692,7 +737,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-sort-desc" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf11f;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf122;" />
</div>
</div>
@ -705,7 +750,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-star" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf120;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf123;" />
</div>
</div>
@ -718,7 +763,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-star-o" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf121;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf124;" />
</div>
</div>
@ -731,7 +776,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-table" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf122;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf125;" />
</div>
</div>
@ -745,7 +790,7 @@
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-times" />
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-close" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf123;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf126;" />
</div>
</div>
@ -758,7 +803,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-trash" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf124;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf127;" />
</div>
</div>
@ -771,7 +816,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-trash-o" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf125;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf128;" />
</div>
</div>
@ -784,7 +829,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-user-circle-o" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf126;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf129;" />
</div>
</div>
@ -797,7 +842,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-user-plus" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf127;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf12a;" />
</div>
</div>
@ -810,7 +855,7 @@
</div>
<div class="usage">
<input class="class" type="text" readonly="readonly" onClick="this.select();" value=".fa-wrench" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf128;" />
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&amp;#xf12b;" />
</div>
</div>

85
public/fonts/fa-dtbl-1.css vendored

@ -38,44 +38,47 @@
font-smoothing: antialiased;
}
.fa-bell::before { content: "\f100"; }
.fa-bell-o::before { content: "\f101"; }
.fa-calendar::before { content: "\f102"; }
.fa-check::before { content: "\f103"; }
.fa-clock-o::before { content: "\f104"; }
.fa-cloud-upload::before { content: "\f105"; }
.fa-code-fork::before { content: "\f106"; }
.fa-download::before { content: "\f107"; }
.fa-eye::before { content: "\f108"; }
.fa-eye-slash::before { content: "\f109"; }
.fa-facebook-square::before { content: "\f10a"; }
.fa-filter::before { content: "\f10b"; }
.fa-flag::before { content: "\f10c"; }
.fa-floppy-o::before, .fa-save::before { content: "\f10d"; }
.fa-gavel::before, .fa-legal::before { content: "\f10e"; }
.fa-github::before { content: "\f10f"; }
.fa-google::before { content: "\f110"; }
.fa-history::before { content: "\f111"; }
.fa-link::before { content: "\f112"; }
.fa-pencil-square-o::before, .fa-edit::before { content: "\f113"; }
.fa-question-circle::before { content: "\f114"; }
.fa-quote-left::before { content: "\f115"; }
.fa-reply::before { content: "\f116"; }
.fa-rss::before { content: "\f117"; }
.fa-search::before { content: "\f118"; }
.fa-share-alt::before { content: "\f119"; }
.fa-sign-in::before { content: "\f11a"; }
.fa-sign-out::before { content: "\f11b"; }
.fa-sliders::before { content: "\f11c"; }
.fa-sort::before { content: "\f11d"; }
.fa-sort-asc::before { content: "\f11e"; }
.fa-sort-desc::before { content: "\f11f"; }
.fa-star::before { content: "\f120"; }
.fa-star-o::before { content: "\f121"; }
.fa-table::before { content: "\f122"; }
.fa-times::before, .fa-close::before { content: "\f123"; }
.fa-trash::before { content: "\f124"; }
.fa-trash-o::before { content: "\f125"; }
.fa-user-circle-o::before { content: "\f126"; }
.fa-user-plus::before { content: "\f127"; }
.fa-wrench::before { content: "\f128"; }
.fa-at::before { content: "\f100"; }
.fa-bell::before { content: "\f101"; }
.fa-bell-o::before { content: "\f102"; }
.fa-calendar::before { content: "\f103"; }
.fa-check::before { content: "\f104"; }
.fa-clock-o::before { content: "\f105"; }
.fa-cloud-upload::before { content: "\f106"; }
.fa-code-fork::before { content: "\f107"; }
.fa-download::before { content: "\f108"; }
.fa-eye::before { content: "\f109"; }
.fa-eye-slash::before { content: "\f10a"; }
.fa-facebook-square::before { content: "\f10b"; }
.fa-filter::before { content: "\f10c"; }
.fa-flag::before { content: "\f10d"; }
.fa-floppy-o::before, .fa-save::before { content: "\f10e"; }
.fa-gavel::before, .fa-legal::before { content: "\f10f"; }
.fa-github::before { content: "\f110"; }
.fa-globe::before { content: "\f111"; }
.fa-google::before { content: "\f112"; }
.fa-history::before { content: "\f113"; }
.fa-key-modern::before { content: "\f114"; }
.fa-link::before { content: "\f115"; }
.fa-pencil-square-o::before, .fa-edit::before { content: "\f116"; }
.fa-question-circle::before { content: "\f117"; }
.fa-quote-left::before { content: "\f118"; }
.fa-reply::before { content: "\f119"; }
.fa-rss::before { content: "\f11a"; }
.fa-search::before { content: "\f11b"; }
.fa-share-alt::before { content: "\f11c"; }
.fa-sign-in::before { content: "\f11d"; }
.fa-sign-out::before { content: "\f11e"; }
.fa-sliders::before { content: "\f11f"; }
.fa-sort::before { content: "\f120"; }
.fa-sort-asc::before { content: "\f121"; }
.fa-sort-desc::before { content: "\f122"; }
.fa-star::before { content: "\f123"; }
.fa-star-o::before { content: "\f124"; }
.fa-table::before { content: "\f125"; }
.fa-times::before, .fa-close::before { content: "\f126"; }
.fa-trash::before { content: "\f127"; }
.fa-trash-o::before { content: "\f128"; }
.fa-user-circle-o::before { content: "\f129"; }
.fa-user-plus::before { content: "\f12a"; }
.fa-wrench::before { content: "\f12b"; }

BIN
public/fonts/fa-dtbl-1.eot

Binary file not shown.

102
public/fonts/fa-dtbl-1.svg

@ -5,7 +5,7 @@
-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">