Compare commits

..

1 Commits

Author SHA1 Message Date
1dca0951e8 🚧 Commence la personnalisation de l'affichage des pages
Pour #12
2022-04-19 16:55:18 +02:00
22 changed files with 746 additions and 44 deletions

View File

@ -1,39 +1,66 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p>
# Diareact <p align="center">
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
A personnal and encrypted diary with Laravel and React. ## About Laravel
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
## Badges Laravel is accessible, powerful, and provides tools required for large, robust applications.
[![Build Status](https://ci.canhelpme.com/api/badges/Shikiryu/diaREact/status.svg?ref=refs/heads/main)](https://ci.canhelpme.com/Shikiryu/maison-montsoult) ## Learning Laravel
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
## Installation If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 1500 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
Install diareact ## Laravel Sponsors
```bash We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).
git clone ssh://gogs@git.shikiryu.com:2200/Shikiryu/diaREact.git
cd diaREact
composer install
npm install
```
## Authors ### Premium Partners
[@shikiryu](https://git.shikiryu.com/Shikiryu) - **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[CMS Max](https://www.cmsmax.com/)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**
- **[Romega Software](https://romegasoftware.com)**
## Contributing
## Acknowledgements Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
- [React](https://github.com/facebook/react/) ## Code of Conduct
- [React MD Editor](https://github.com/uiwjs/react-md-editor)
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
## Security Vulnerabilities
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
## License ## License
[MIT](https://choosealicense.com/licenses/mit/) The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

View File

@ -45,12 +45,14 @@ class PageController extends Controller
} }
}, Storage::disk('pages')->files(Auth::user()->getAuthIdentifier()))); }, Storage::disk('pages')->files(Auth::user()->getAuthIdentifier())));
/** @var \App\Models\User $user */
$user = Auth::user(); $user = Auth::user();
return view('pages.index', [ return view('pages.index', [
'start_date'=> min((new DateTime())->sub(new DateInterval('P1Y')), $user->created_at), 'start_date' => min((new DateTime())->sub(new DateInterval('P1Y')), $user->created_at),
'checkword' => $user->checkword, 'checkword' => $user->checkword,
'pages' => $pages, 'settings' => json_encode($user->getSettings()),
'pages' => $pages,
]); ]);
} }
@ -124,7 +126,7 @@ class PageController extends Controller
*/ */
public function edit($id) public function edit($id)
{ {
throw new MethodNotAllowedHttpException('You can\'t edit a page.'); throw new MethodNotAllowedHttpException(['GET'], 'You can\'t edit a page.');
} }
/** /**
@ -137,7 +139,7 @@ class PageController extends Controller
*/ */
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
throw new MethodNotAllowedHttpException('You can\'t edit a page.'); throw new MethodNotAllowedHttpException(['GET'], 'You can\'t edit a page.');
} }
/** /**

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Http\Requests\User\SettingsRequest;
use App\Http\Requests\User\WordCheckRequest; use App\Http\Requests\User\WordCheckRequest;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@ -23,4 +24,26 @@ class UserController extends Controller
return response()->json(['success' => true]); return response()->json(['success' => true]);
} }
public function settings()
{
return view('user.settings', [
'settings' => Auth::user()->getSettings(),
]);
}
public function storeSettings(SettingsRequest $request)
{
$validated = $request->validated();
$user = User::where('id', Auth::user()->getAuthIdentifier())->firstOrFail();
foreach ($validated as $name => $value) {
$user->{$name} = $value;
}
$user->save();
Auth::setUser($user);
$request->session()->flash('status', __('Settings saved!'));
return redirect()->route('user.settings');
}
} }

View File

@ -0,0 +1,34 @@
<?php
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class SettingsRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'text_color' => ['required', 'string', 'max:7'],
'background_color' => ['required', 'string', 'max:7'],
'font' => ['required', 'string', 'max:255'],
'font_size' => ['required', 'numeric'],
'line_spacing' => ['required', 'numeric'],
];
}
}

View File

@ -33,6 +33,14 @@ class User extends Authenticatable
'remember_token', 'remember_token',
]; ];
protected $settings = [
'text_color',
'background_color',
'font',
'font_size',
'line_spacing',
];
/** /**
* The attributes that should be cast. * The attributes that should be cast.
* *
@ -41,4 +49,17 @@ class User extends Authenticatable
protected $casts = [ protected $casts = [
'email_verified_at' => 'datetime', 'email_verified_at' => 'datetime',
]; ];
/**
* @return array
*/
public function getSettings()
{
$settings = [];
foreach ($this->settings as $setting) {
$settings[$setting] = $this->{$setting};
}
return $settings;
}
} }

View File

@ -6,13 +6,15 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^7.3|^8.0", "php": "^7.3|^8.0",
"doctrine/dbal": "^3.3",
"fruitcake/laravel-cors": "^2.0", "fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1", "guzzlehttp/guzzle": "^7.0.1",
"kzykhys/yaml-front-matter": "^1.0", "kzykhys/yaml-front-matter": "^1.0",
"laravel/framework": "^9.0", "laravel/framework": "^9.0",
"laravel/sanctum": "^2.11", "laravel/sanctum": "^2.11",
"laravel/tinker": "^2.5", "laravel/tinker": "^2.5",
"laravel/ui": "^3.4" "laravel/ui": "^3.4",
"ext-json": "*"
}, },
"require-dev": { "require-dev": {
"spatie/laravel-ignition": "^1.0", "spatie/laravel-ignition": "^1.0",

398
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "af7035cb5f906bc34893e53d97e6656f", "content-hash": "4b6bb4a29b9cbd7a05ba0cc319b1aa4c",
"packages": [ "packages": [
{ {
"name": "asm89/stack-cors", "name": "asm89/stack-cors",
@ -197,6 +197,353 @@
}, },
"time": "2021-08-13T13:06:58+00:00" "time": "2021-08-13T13:06:58+00:00"
}, },
{
"name": "doctrine/cache",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "331b4d5dbaeab3827976273e9356b3b453c300ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/331b4d5dbaeab3827976273e9356b3b453c300ce",
"reference": "331b4d5dbaeab3827976273e9356b3b453c300ce",
"shasum": ""
},
"require": {
"php": "~7.1 || ^8.0"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
"alcaeus/mongo-php-adapter": "^1.1",
"cache/integration-tests": "dev-master",
"doctrine/coding-standard": "^8.0",
"mongodb/mongodb": "^1.1",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"predis/predis": "~1.0",
"psr/cache": "^1.0 || ^2.0 || ^3.0",
"symfony/cache": "^4.4 || ^5.2 || ^6.0@dev",
"symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev"
},
"suggest": {
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
"homepage": "https://www.doctrine-project.org/projects/cache.html",
"keywords": [
"abstraction",
"apcu",
"cache",
"caching",
"couchdb",
"memcached",
"php",
"redis",
"xcache"
],
"support": {
"issues": "https://github.com/doctrine/cache/issues",
"source": "https://github.com/doctrine/cache/tree/2.1.1"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
"type": "tidelift"
}
],
"time": "2021-07-17T14:49:29+00:00"
},
{
"name": "doctrine/dbal",
"version": "3.3.5",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "719663b15983278227669c8595151586a2ff3327"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/719663b15983278227669c8595151586a2ff3327",
"reference": "719663b15983278227669c8595151586a2ff3327",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2",
"doctrine/cache": "^1.11|^2.0",
"doctrine/deprecations": "^0.5.3",
"doctrine/event-manager": "^1.0",
"php": "^7.3 || ^8.0",
"psr/cache": "^1|^2|^3",
"psr/log": "^1|^2|^3"
},
"require-dev": {
"doctrine/coding-standard": "9.0.0",
"jetbrains/phpstorm-stubs": "2021.1",
"phpstan/phpstan": "1.5.3",
"phpstan/phpstan-strict-rules": "^1.1",
"phpunit/phpunit": "9.5.16",
"psalm/plugin-phpunit": "0.16.1",
"squizlabs/php_codesniffer": "3.6.2",
"symfony/cache": "^5.2|^6.0",
"symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0",
"vimeo/psalm": "4.22.0"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\DBAL\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
"keywords": [
"abstraction",
"database",
"db2",
"dbal",
"mariadb",
"mssql",
"mysql",
"oci8",
"oracle",
"pdo",
"pgsql",
"postgresql",
"queryobject",
"sasql",
"sql",
"sqlite",
"sqlserver",
"sqlsrv"
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/3.3.5"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
"type": "tidelift"
}
],
"time": "2022-04-05T09:50:18+00:00"
},
{
"name": "doctrine/deprecations",
"version": "v0.5.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "9504165960a1f83cc1480e2be1dd0a0478561314"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314",
"reference": "9504165960a1f83cc1480e2be1dd0a0478561314",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0|^7.0|^8.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0",
"psr/log": "^1.0"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v0.5.3"
},
"time": "2021-03-21T12:59:47+00:00"
},
{
"name": "doctrine/event-manager",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/event-manager.git",
"reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f",
"reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"conflict": {
"doctrine/common": "<2.9@dev"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"phpunit/phpunit": "^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
},
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
}
],
"description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
"keywords": [
"event",
"event dispatcher",
"event manager",
"event system",
"events"
],
"support": {
"issues": "https://github.com/doctrine/event-manager/issues",
"source": "https://github.com/doctrine/event-manager/tree/1.1.x"
},
"funding": [
{
"url": "https://www.doctrine-project.org/sponsorship.html",
"type": "custom"
},
{
"url": "https://www.patreon.com/phpdoctrine",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
"type": "tidelift"
}
],
"time": "2020-05-29T18:28:51+00:00"
},
{ {
"name": "doctrine/inflector", "name": "doctrine/inflector",
"version": "2.0.4", "version": "2.0.4",
@ -2305,6 +2652,55 @@
], ],
"time": "2021-12-04T23:24:31+00:00" "time": "2021-12-04T23:24:31+00:00"
}, },
{
"name": "psr/cache",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/cache.git",
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for caching libraries",
"keywords": [
"cache",
"psr",
"psr-6"
],
"support": {
"source": "https://github.com/php-fig/cache/tree/3.0.0"
},
"time": "2021-02-03T23:26:27+00:00"
},
{ {
"name": "psr/container", "name": "psr/container",
"version": "2.0.2", "version": "2.0.2",

View File

@ -0,0 +1,48 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('text_color')->default('#000000');
$table->string('background_color')->default('#FFFFFF');
$table->string('font')->default('Arial');
$table->float('font_size', 3, 1)->default(16);
$table->float('line_spacing', 2, 3)->default(1.5);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('text_color');
});
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('background_color');
});
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('font');
});
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('font_size');
});
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('line_spacing');
});
}
};

View File

@ -24,6 +24,7 @@ const sessionPassphrase = sessionStorage.getItem("key") as string;
let pages: IList[] = []; let pages: IList[] = [];
let getPageContentUrl, let getPageContentUrl,
postUrl, postUrl,
settings,
removeUrl, removeUrl,
checkword, checkword,
startDate, startDate,
@ -33,7 +34,8 @@ if (app) {
getPageContentUrl = "" + app.getAttribute('data-url'); getPageContentUrl = "" + app.getAttribute('data-url');
pages = JSON.parse("" + app.getAttribute('data-list')) as IList[]; pages = JSON.parse("" + app.getAttribute('data-list')) as IList[];
postUrl = "" + app.getAttribute('data-post'); postUrl = "" + app.getAttribute('data-post');
startDate = "" + app.getAttribute('data-start'); startDate = "" + app.getAttribute('data-start');
settings = JSON.parse("" + app.getAttribute('data-settings'));
removeUrl = "" + app.getAttribute('data-remove'); removeUrl = "" + app.getAttribute('data-remove');
csrf = "" + app.getAttribute('data-csrf'); csrf = "" + app.getAttribute('data-csrf');
checkword = "" + app.getAttribute('data-checkword'); checkword = "" + app.getAttribute('data-checkword');
@ -195,6 +197,7 @@ function App() {
csrf={csrf} csrf={csrf}
removeUrl={removeUrl} removeUrl={removeUrl}
loadPages={loadPages} loadPages={loadPages}
settings={settings}
setAllLoaded={setAllLoaded} setAllLoaded={setAllLoaded}
/> />
<Divider/> <Divider/>

View File

@ -5,7 +5,7 @@ import {IPages} from "../../interfaces/IPages";
import {IList} from "../../interfaces/IList"; import {IList} from "../../interfaces/IList";
import {isAllLoadedLocally} from "../../utils"; import {isAllLoadedLocally} from "../../utils";
export default function Pages({pages, url, removeUrl, csrf, passphrase, loadPages, setAllLoaded}: IPages) { export default function Pages({pages, url, removeUrl, csrf, passphrase, loadPages, settings, setAllLoaded}: IPages) {
const isPassphraseSet = passphrase !== null; const isPassphraseSet = passphrase !== null;
const perPage = 1; const perPage = 1;
const total = pages.length; const total = pages.length;
@ -24,26 +24,22 @@ export default function Pages({pages, url, removeUrl, csrf, passphrase, loadPage
const json = await response.json(); const json = await response.json();
if (json.success) { if (json.success) {
console.log(listPages.length);
const newListPages = listPages.filter(function (value) { const newListPages = listPages.filter(function (value) {
console.log(value.id);
return value.id !== id; return value.id !== id;
}); });
setListPages(newListPages); setListPages(newListPages);
console.log(newListPages.length);
console.log(listPages.length);
updateListPages(newListPages.slice((currentPage - 1) * perPage, ((currentPage - 1) * perPage) + perPage).map(page => updateListPages(newListPages.slice((currentPage - 1) * perPage, ((currentPage - 1) * perPage) + perPage).map(page =>
<Page page={page} url={url} remove={removePage} passphrase={passphrase} key={page.id}/>)); <Page page={page} url={url} remove={removePage} settings={settings} passphrase={passphrase} key={page.id}/>));
} }
} }
const [listPagesDisplayed, updateListPages] = React.useState(listPages.slice((currentPage-1) * perPage, ((currentPage-1) * perPage) + perPage ).map(page => const [listPagesDisplayed, updateListPages] = React.useState(listPages.slice((currentPage-1) * perPage, ((currentPage-1) * perPage) + perPage ).map(page =>
<Page page={page} url={url} remove={removePage} passphrase={passphrase} key={page.id} />)); <Page page={page} url={url} remove={removePage} settings={settings} passphrase={passphrase} key={page.id} />));
const handlePageChange = (event: React.ChangeEvent<unknown>, value: number) => { const handlePageChange = (event: React.ChangeEvent<unknown>, value: number) => {
setPage(value); setPage(value);
updateListPages(listPages.slice((value-1) * perPage, ((value-1) * perPage) + perPage).map(page => updateListPages(listPages.slice((value-1) * perPage, ((value-1) * perPage) + perPage).map(page =>
<Page page={page} url={url} remove={removePage} passphrase={passphrase} key={page.id}/>)); <Page page={page} url={url} settings={settings} remove={removePage} passphrase={passphrase} key={page.id}/>));
}; };
const loadAllPages = function() { const loadAllPages = function() {
@ -61,7 +57,7 @@ export default function Pages({pages, url, removeUrl, csrf, passphrase, loadPage
localStorage.setItem(page.id + "text", json.content); localStorage.setItem(page.id + "text", json.content);
updateListPages([]); updateListPages([]);
updateListPages(listPages.slice((currentPage-1) * perPage, ((currentPage-1) * perPage) + perPage).map(page => updateListPages(listPages.slice((currentPage-1) * perPage, ((currentPage-1) * perPage) + perPage).map(page =>
<Page page={page} url={url} remove={removePage} passphrase={passphrase} key={page.id}/>)); <Page page={page} url={url} remove={removePage} settings={settings} passphrase={passphrase} key={page.id}/>));
} }
} }

View File

@ -3,7 +3,7 @@ import {
AlertTitle, AlertTitle,
Card, CardContent, Card, CardContent,
CardHeader, Collapse, CardHeader, Collapse,
Grid, IconButton Grid, IconButton,
} from '@mui/material'; } from '@mui/material';
import MoreVertIcon from '@mui/icons-material/MoreVert'; import MoreVertIcon from '@mui/icons-material/MoreVert';
import * as React from 'react'; import * as React from 'react';
@ -12,7 +12,7 @@ import {Delete, Download} from "@mui/icons-material";
import MDEditor from "@uiw/react-md-editor"; import MDEditor from "@uiw/react-md-editor";
import {PropPage} from "../../interfaces/PropPage"; import {PropPage} from "../../interfaces/PropPage";
const Page = function({page, url, passphrase, remove}: PropPage) { const Page = function({page, url, passphrase, settings, remove}: PropPage) {
const [more, setMore] = React.useState<boolean>(false); const [more, setMore] = React.useState<boolean>(false);
const handleMoreClick = () => { setMore(!more); }; const handleMoreClick = () => { setMore(!more); };
@ -49,10 +49,22 @@ const Page = function({page, url, passphrase, remove}: PropPage) {
); );
} }
return ( return (
<Grid item xs={12} sm={12} md={12} id={page.id}> <Grid item xs={12} sm={12} md={12} id={page.id}
sx={{
bgcolor: settings.background_color,
color: settings.text_color,
fontSize: settings.font_size + "px",
fontFamily: settings.font,
lineHeight: settings.line_spacing
}}>
<Card> <Card>
<CardHeader <CardHeader
sx={{
bgcolor: settings.background_color,
color: settings.text_color
}}
action={ action={
icons icons
} }
@ -65,7 +77,13 @@ const Page = function({page, url, passphrase, remove}: PropPage) {
</IconButton> </IconButton>
</Collapse> </Collapse>
</CardHeader> </CardHeader>
<CardContent> <CardContent sx={{
backgroundColor: settings.background_color,
color: settings.text_color,
fontSize: settings.font_size + "px",
fontFamily: settings.font,
lineHeight: settings.line_spacing
}}>
<MDEditor.Markdown source={content} /> <MDEditor.Markdown source={content} />
</CardContent> </CardContent>
</Card> </Card>

View File

@ -13,6 +13,12 @@ export default function BasicMenu({nickname}) {
setAnchorEl(null); setAnchorEl(null);
}; };
function gotoSettings() {
const currentHref = location.href.split('/');
currentHref.pop();
location.href = currentHref.join('/') + '/settings';
}
function logout() { function logout() {
const logoutForm: HTMLFormElement = document.getElementById("logout-form") as HTMLFormElement; const logoutForm: HTMLFormElement = document.getElementById("logout-form") as HTMLFormElement;
logoutForm.submit(); logoutForm.submit();
@ -39,7 +45,7 @@ export default function BasicMenu({nickname}) {
'aria-labelledby': 'basic-button', 'aria-labelledby': 'basic-button',
}} }}
> >
{/*<MenuItem onClick={handleClose}>My account</MenuItem>*/} <MenuItem onClick={gotoSettings}>Settings</MenuItem>
<MenuItem onClick={logout}>Logout</MenuItem> <MenuItem onClick={logout}>Logout</MenuItem>
</Menu> </Menu>
</div> </div>

View File

@ -28,6 +28,12 @@ export default function MobileMenu({nickname}) {
setState( open ); setState( open );
}; };
function gotoSettings() {
const currentHref = location.href.split('/');
currentHref.pop();
location.href = currentHref.join('/') + '/settings';
}
function logout() { function logout() {
const logoutForm: HTMLFormElement = document.getElementById("logout-form") as HTMLFormElement; const logoutForm: HTMLFormElement = document.getElementById("logout-form") as HTMLFormElement;
logoutForm.submit(); logoutForm.submit();
@ -53,7 +59,7 @@ export default function MobileMenu({nickname}) {
onKeyDown={toggleDrawer(false)} onKeyDown={toggleDrawer(false)}
> >
<List> <List>
<ListItem button key={"user"}> <ListItem key={"user"}>
<ListItemIcon> <ListItemIcon>
<MailIcon /> <MailIcon />
</ListItemIcon> </ListItemIcon>
@ -62,7 +68,13 @@ export default function MobileMenu({nickname}) {
</List> </List>
<Divider /> <Divider />
<List> <List>
<ListItem button key={"user.logout"} onClick={logout}> <ListItem key={"user.settings"} onClick={gotoSettings}>
<ListItemIcon>
<MailIcon />
</ListItemIcon>
<ListItemText primary={"Settings"} />
</ListItem>
<ListItem key={"user.logout"} onClick={logout}>
<ListItemIcon> <ListItemIcon>
<InboxIcon /> <InboxIcon />
</ListItemIcon> </ListItemIcon>

View File

@ -1,5 +1,6 @@
import {IList} from "./IList"; import {IList} from "./IList";
import * as React from "react"; import * as React from "react";
import {ISettings} from "./ISettings";
export interface IPages { export interface IPages {
pages: IList[]; pages: IList[];
@ -7,6 +8,7 @@ export interface IPages {
removeUrl: string; removeUrl: string;
csrf: string; csrf: string;
passphrase: string; passphrase: string;
settings: ISettings;
loadPages: React.MutableRefObject<() => void>; loadPages: React.MutableRefObject<() => void>;
setAllLoaded: React.Dispatch<React.SetStateAction<boolean>>; setAllLoaded: React.Dispatch<React.SetStateAction<boolean>>;
} }

View File

@ -0,0 +1,7 @@
export interface ISettings {
background_color: string;
text_color: string;
font_size: number;
font: string;
line_spacing: number;
}

View File

@ -1,9 +1,11 @@
import { Ref } from "react"; import { Ref } from "react";
import {IList} from "./IList"; import {IList} from "./IList";
import {ISettings} from "./ISettings";
export interface PropPage { export interface PropPage {
page: IList; page: IList;
url: string; url: string;
settings: ISettings;
passphrase: string; passphrase: string;
remove: (id) => void; remove: (id) => void;
ref: Ref<IList>; ref: Ref<IList>;

View File

@ -7,6 +7,9 @@
<title>{{ config('app.name', 'Laravel') }}</title> <title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">
<!-- Styles --> <!-- Styles -->
<link rel="stylesheet" href="{{ asset('css/app.css') }}"> <link rel="stylesheet" href="{{ asset('css/app.css') }}">

View File

@ -7,6 +7,7 @@
<title>{{ config('app.name', 'Laravel') }}</title> <title>{{ config('app.name', 'Laravel') }}</title>
<link rel="stylesheet" href="{{ asset('css/app.css') }}"> <link rel="stylesheet" href="{{ asset('css/app.css') }}">
<style> <style>
body { font-family: 'Nunito', sans-serif; }
.gradient { .gradient {
background: rgb(108,99,255); background: rgb(108,99,255);
background: linear-gradient(90deg, rgba(108,99,255,1) 0%, rgba(0,212,255,1) 100%); background: linear-gradient(90deg, rgba(108,99,255,1) 0%, rgba(0,212,255,1) 100%);

View File

@ -17,6 +17,7 @@
data-remove="{{ route('pages.destroy', ['page' => 'replace_me']) }}" data-remove="{{ route('pages.destroy', ['page' => 'replace_me']) }}"
data-csrf="{{ csrf_token() }}" data-csrf="{{ csrf_token() }}"
data-checkword="{{ $checkword }}" data-checkword="{{ $checkword }}"
data-settings="{{ $settings }}"
> >
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
<x-app-layout> <x-app-layout>
<x-slot name="header"> <x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight"> <h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('First connection') }} {{ __('Première connexion') }}
</h2> </h2>
</x-slot> </x-slot>

View File

@ -0,0 +1,96 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Settings') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<!-- Session Status -->
<x-auth-session-status class="mb-4" :status="session('status')" />
<!-- Validation Errors -->
<x-auth-validation-errors class="mb-4" :errors="$errors" />
<div class="p-6 bg-white border-b border-gray-200">
<form action="{{ route('user.storeSettings') }}" method="post">
@csrf
<div class="md:flex mb-6">
<div class="md:w-1/3">
<label class="block text-gray-600 font-bold md:text-left mb-3 md:mb-0 pr-4" for="text_color">
{{ __('Text color:') }}
</label>
</div>
<div class="md:w-2/3">
<input class="form-input block w-full focus:bg-white" id="text_color" name="text_color" type="color" value="{{ $settings['text_color'] }}">
</div>
</div>
<div class="md:flex mb-6">
<div class="md:w-1/3">
<label class="block text-gray-600 font-bold md:text-left mb-3 md:mb-0 pr-4" for="background_color">
{{ __('Background color:') }}
</label>
</div>
<div class="md:w-2/3">
<input class="form-input block w-full focus:bg-white" id="background_color" name="background_color" type="color" value="{{ $settings['background_color'] }}">
</div>
</div>
<div class="md:flex mb-6">
<div class="md:w-1/3">
<label class="block text-gray-600 font-bold md:text-left mb-3 md:mb-0 pr-4" for="font">
{{ __('Font:') }}
</label>
</div>
<div class="md:w-2/3">
<select class="form-select block w-full focus:bg-white" id="font" name="font">
<option value="Arial" {{ $settings['font'] === 'Arial' ? 'selected' : '' }}>Arial</option>
<option value="Pacifico" {{ $settings['font'] === 'Pacifico' ? 'selected' : '' }}>Pacifico</option>
</select>
</div>
</div>
<div class="md:flex mb-6">
<div class="md:w-1/3">
<label class="block text-gray-600 font-bold md:text-left mb-3 md:mb-0 pr-4" for="font_size">
{{ __('Font size:') }}
</label>
</div>
<div class="md:w-2/3">
<input class="form-input block w-full focus:bg-white" id="font_size" name="font_size" type="range" min="12" max="18" step="1" value="{{ $settings['font_size'] }}" oninput="this.nextElementSibling.value = this.value">
<output>{{ $settings['font_size'] }}</output>
</div>
</div>
<div class="md:flex mb-6">
<div class="md:w-1/3">
<label class="block text-gray-600 font-bold md:text-left mb-3 md:mb-0 pr-4" for="line_spacing">
{{ __('Line spacing:') }}
</label>
</div>
<div class="md:w-2/3">
<input class="form-input block w-full focus:bg-white" id="line_spacing" name="line_spacing" type="range" min="1" max="3" step="0.1" value="{{ $settings['line_spacing'] }}" oninput="this.nextElementSibling.value = this.value">
<output>{{ $settings['line_spacing'] }}</output>
</div>
</div>
<div class="md:flex md:items-center">
<div class="md:w-1/3"></div>
<div class="md:w-2/3">
<button class="shadow bg-yellow-700 hover:bg-yellow-500 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded" type="submit">
{{ __('Save preference') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>

View File

@ -27,6 +27,8 @@ Route::resource('pages', PageController::class)
Route::get('/first', [UserController::class, 'first'])->middleware(['auth', 'auth.passphrase'])->name('user.first'); Route::get('/first', [UserController::class, 'first'])->middleware(['auth', 'auth.passphrase'])->name('user.first');
Route::post('/first', [UserController::class, 'storeFirst'])->middleware(['auth', 'auth.passphrase'])->name('user.storeFirst'); Route::post('/first', [UserController::class, 'storeFirst'])->middleware(['auth', 'auth.passphrase'])->name('user.storeFirst');
Route::get('/settings', [UserController::class, 'settings'])->middleware(['auth'])->name('user.settings');
Route::post('/settings', [UserController::class, 'storeSettings'])->middleware(['auth'])->name('user.storeSettings');
Route::get('/dashboard', function () { Route::get('/dashboard', function () {
return redirect(\route('pages.index')); return redirect(\route('pages.index'));