use App\Models\CollectionList;
use App\Models\Song;
use Cubist\Backpack\Http\Controllers\CubistPWAController;
+use Illuminate\Support\Facades\Session;
class FrontController extends Controller
public function collection($name)
{
$collection = Collection::where('slug', $name)->first();
-
if (null === $collection) {
return self::defaultCollection();
}
+ if ($p = $this->checkPassword($collection)) {
+ return $p;
+ }
$lists = CollectionList::where('collection', $collection->id)->get();
$songs = $this->_getSongsOfCollection($collection->id, $lists);
- return view('collection', ['songs' => $songs, 'collection' => $collection, 'collection_songs' => $songs, 'collection_lists' => $lists]);
+ return view('collection', ['menu' => true, 'songs' => $songs, 'collection' => $collection, 'collection_songs' => $songs, 'collection_lists' => $lists]);
+ }
+
+ public function checkPassword(Collection $collection)
+ {
+ if (!$collection->password) {
+ return false;
+ }
+ $error = false;
+ if (request()->has('password')) {
+ if (request('password') === $collection->password) {
+ Session::put('loggedin-' . $collection->id, '1');
+ } else {
+ $error = true;
+ }
+ }
+ if (Session::get('loggedin-' . $collection->id, '0') == '1') {
+ return false;
+ }
+ return view('login', ['menu' => false, 'collection' => $collection, 'error' => $error]);
}
public function song($collection, $song)
if (null === $song) {
abort(404);
}
+ if ($p = $this->checkPassword($collection)) {
+ return $p;
+ }
$lists = CollectionList::where('collection', $collection->id)->get();
- return view('song', ['song' => $song, 'collection' => $collection, 'collection_songs' => $this->_getSongsOfCollection($collection->id, $lists), 'collection_lists' => $lists]);
+ return view('song', ['menu' => true, 'song' => $song, 'collection' => $collection, 'collection_songs' => $this->_getSongsOfCollection($collection->id, $lists), 'collection_lists' => $lists]);
}
protected function _getSongsOfCollection($id, $lists)
namespace App\Models;
use Cubist\Backpack\Http\Controllers\CubistPWAController;
+use Cubist\Backpack\Magic\Fields\Checkbox;
use Cubist\Backpack\Magic\Fields\Color;
use Cubist\Backpack\Magic\Fields\Images;
use Cubist\Backpack\Magic\Fields\Slug;
use Cubist\Backpack\Magic\Fields\Table;
+use Cubist\Backpack\Magic\Fields\Text;
use Cubist\Backpack\Magic\Models\CubistMagicAbstractModel;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
'singular' => 'collection',
'plural' => 'collections'];
- public function setFields()
+
+ public function setfields()
{
parent::setFields();
$this->addField('name', 'Text', 'Name', ['column' => true]);
$this->addField('icon', Images::class, 'Icône');
$this->addField('theme_color', Color::class, 'Couleur d\'accentuation');
$this->addField('splashscreen_color', Color::class, 'Couleur de fond du splashscreen');
+ $this->addField('password', Text::class, 'Mot de passe', ['hint' => 'Laisser vide pour désactiver']);
+ $this->addField('transpose', Checkbox::class, 'Activer la transposition', ['default' => true, 'database_default' => true]);
+ $this->addField('download_assets', Checkbox::class, 'Activer le téléchargement', ['default' => false, 'database_default' => false]);
}
public function registerMediaConversions(Media $media = null): void
use App\SubForm\AudioTrack;
use App\SubForm\SongPortion;
use Cubist\Backpack\Magic\Fields\BunchOfFieldsMultiple;
+use Cubist\Backpack\Magic\Fields\Checkbox;
+use Cubist\Backpack\Magic\Fields\Files;
+use Cubist\Backpack\Magic\Fields\SelectFromArray;
use Cubist\Backpack\Magic\Fields\SelectFromModel;
use Cubist\Backpack\Magic\Models\CubistMagicAbstractModel;
$this->addField('artist', 'Text', 'Artist', ['column' => true]);
$this->addField('key', Tone::class, 'Key', ['column' => true]);
$this->addField('mode', Mode::class, 'Mode', ['column' => true]);
+ $this->addField('chorale', Checkbox::class, 'Chorale', ['default' => false, 'database_default' => false]);
$this->addField('collections', \App\Field\CollectionList::class, 'Collections');
$this->addField('tempo', Tempo::class, 'Suggested tempo', ['column' => true, 'default' => 80]);
- $this->addField('lyrics', BunchOfFieldsMultiple::class, 'Song Parts', ['bunch' => SongPortion::class, 'new_label' => 'New song part']);
+ $this->addField('partition', Files::class, 'Partition', ['acceptedFiles' => '*.pdf', 'when' => ['chorale' => 1]]);
+ $this->addField('lyrics_doc', Files::class, 'Paroles', ['acceptedFiles' => '*.doc', 'when' => ['chorale' => 1]]);
$this->addField('audio', BunchOfFieldsMultiple::class, 'Audio tracks', ['bunch' => AudioTrack::class, 'new_label' => 'New audio track']);
+ $this->addField('lyrics', BunchOfFieldsMultiple::class, 'Song Parts', ['bunch' => SongPortion::class, 'new_label' => 'New song part', 'when' => ['chorale' => 0]]);
// $this->addField('youtube', URL::class, 'Youtube link');
// $this->addField('spotify', URL::class, 'Spotify link');
// $this->addField('credits', 'Textarea', 'Credits');
|
*/
- 'lifetime' => env('SESSION_LIFETIME', 120),
+ 'lifetime' => env('SESSION_LIFETIME', 525600),
'expire_on_close' => false,
@echo off
cls
-C:\tools\cygwin\bin\ssh.exe -t root@192.168.13.7 'docker exec -it songbook /bin/bash'
+C:\tools\cygwin\bin\ssh.exe -t root@her2.cubedesigners.com 'docker exec -it songbook /bin/bash'
font-weight: 700
src: url('fonts/roboto-condensed-700.woff2') format('woff2')
+$slab: 'Roboto Slab', sans-serif
+
*
margin: 0
padding: 0
box-sizing: border-box
h1, h2, h3, h4, h5, h6
- font-family: 'Roboto Slab', sans-serif
+ font-family: $slab
font-weight: 500
a
right: 0
z-index: 100
+ &.nomenu
+ .placeholder
+ padding: 10px
+
@media print
position: absolute
bottom: 0
left: 0
+form
+ .error
+ text-align: center
+ padding: 20px 0 0 0
+ color: #cc0000
+
+ input
+ display: block
+ margin: 25px auto
+ width: 100%
+ max-width: 400px
+ text-align: center
+ border-radius: 5px
+ border: 0
+ padding: 15px
+ font-size: 16px
+ font-weight: 500
+ font-family: $slab
+
+ input[type=password]
+ text-align: left
+ outline-color: var(--theme-color)
+
+ input[type=submit]
+ background-color: var(--theme-color)
+ color: #fff
+ cursor: pointer
+
+
@import "../../node_modules/mmenu-light/dist/mmenu-light.css"
@import "../../node_modules/plyr/dist/plyr.css"
document.addEventListener("DOMContentLoaded", () => {
var darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
- const menu = new MmenuLight(document.querySelector("#menu"));
+ if ($('#menu').length > 0) {
+ const menu = new MmenuLight(document.querySelector("#menu"));
- const navigator = menu.navigation({theme: darkMode ? 'dark' : 'light'});
- const drawer = menu.offcanvas();
- document.querySelector('#menu-icon')
- .addEventListener('click', (evnt) => {
- evnt.preventDefault();
- drawer.open();
- });
+ const navigator = menu.navigation({theme: darkMode ? 'dark' : 'light'});
+ const drawer = menu.offcanvas();
+ document.querySelector('#menu-icon')
+ .addEventListener('click', (evnt) => {
+ evnt.preventDefault();
+ drawer.open();
+ });
- var mc = new Hammer(document.getElementsByTagName('main').item(0), {touchAction: "auto"})
- mc.on('swiperight', function (e) {
- if (e.distance > 100 && e.overallVelocityX > 0.4) {
- drawer.open();
- return false;
- }
- return true;
- });
+ var mc = new Hammer(document.getElementsByTagName('main').item(0), {touchAction: "auto"})
+
+ mc.on('swiperight', function (e) {
+ if (e.distance > 100 && e.overallVelocityX > 0.4) {
+ drawer.open();
+ return false;
+ }
+ return true;
+ });
+ }
$('body').addClass('init');
});
$(this).hide();
var audio = window.getOption('audio').toString();
- var tone = window.getOption('audio_' + audio + '_tone').toString();
+ var t = window.getOption('audio_' + audio + '_tone');
+ if (t === undefined) {
+ t = 0;
+ }
+ var tone = t.toString();
if (tone === 'undefined') {
tone = '0';
}
@php
$preload=[];
@endphp
-@section('title', $collection->name.' Songbook')
+@section('title', $collection->name)
@section('content')
@include('header',['title'=>$collection->name,'subtitle'=>''])
<div id="header-space">
</div>
-<header>
+<header @if(!$menu)
+ class="nomenu"
+ @endif
+>
<div class="placeholder">
- <a href="#" id="menu-icon">
- <svg viewBox="0 0 100 80" width="40" height="40">
- <rect fill="currentColor" width="100" height="5"></rect>
- <rect fill="currentColor" y="30" width="100" height="5"></rect>
- <rect fill="currentColor" y="60" width="100" height="5"></rect>
- </svg>
- </a>
- <h1>{{$title}}</h1>
+ @if($menu)
+ <a href="#" id="menu-icon">
+ <svg viewBox="0 0 100 80" width="40" height="40">
+ <rect fill="currentColor" width="100" height="5"></rect>
+ <rect fill="currentColor" y="30" width="100" height="5"></rect>
+ <rect fill="currentColor" y="60" width="100" height="5"></rect>
+ </svg>
+ </a>
+ <h1>{{$title}}</h1>
+ @else
+ <h1>{{$title}}</h1>
+ @endif
+
@if($subtitle)
<h2>{{$subtitle}}</h2>
@endif
@include('menu')
-<!DOCTYPE html>
+ <!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<main class="content page" id="page">
@yield('content')
</main>
-<nav id="floating">
- @yield('floating')
-</nav>
-@yield('menu')
+@if($menu)
+ <nav id="floating">
+ @yield('floating')
+ </nav>
+ @yield('menu')
+@endif
<script>
// Check that service workers are supported
if ('serviceWorker' in navigator) {
--- /dev/null
+@extends('layout')
+@php
+ $preload=[];
+@endphp
+@section('title', $collection->name)
+
+@section('content')
+ @include('header',['title'=>$collection->name,'subtitle'=>''])
+ <form action="" method="post">
+ @if($error)
+ <p class="error">Mot de passe erroné</p>
+ @endif
+ @csrf
+ <input type="password" name="password" placeholder="Mot de passe">
+ <input type="submit" value="Connexion">
+ </form>
+@endsection
<li><a href="/{{$collection->slug}}">📖 {{__('Home')}}</a></li>
<li><span>🎶 {{__('Songs')}}</span>
<ul>
- @foreach($collection_songs as $csong)
- @if(!in_array($collection->id, $csong->collections))
- @continue
- @endif
- @include('menu_song')
- @endforeach
- @foreach($collection_lists as $list)
- <li><span>📒 {{$list->name}}</span>
- <ul>
- @foreach($collection_songs as $csong)
- @if(!in_array($collection->id.'_'.$list->id, $csong->collections))
- @continue
- @endif
- @include('menu_song')
- @endforeach
- </ul>
- </li>
- @endforeach
+ @if(isset($collection_songs))
+ @foreach($collection_songs as $csong)
+ @if(!in_array($collection->id, $csong->collections))
+ @continue
+ @endif
+ @include('menu_song')
+ @endforeach
+ @endif
+ @if(isset($collection_lists))
+ @foreach($collection_lists as $list)
+ <li><span>📒 {{$list->name}}</span>
+ <ul>
+ @foreach($collection_songs as $csong)
+ @if(!in_array($collection->id.'_'.$list->id, $csong->collections))
+ @continue
+ @endif
+ @include('menu_song')
+ @endforeach
+ </ul>
+ </li>
+ @endforeach
+ @endif
</ul>
</li>
@if(isset($song))
@if($song->hasChords())
- <li><a href="#" class="noaction">🎤 {{__('Show lyrics')}} <input type="checkbox" class="checkbox-switch"
- name="show_lyrics_{{$song->id}}"
- data-default="1"></a></li>
- <li><a href="#" class="noaction">🎼 {{__('Show chords')}} <input type="checkbox" class="checkbox-switch"
- name="show_chords_{{$song->id}}"
- data-default="1"></a></li>
+ <li><a href="#" class="noaction">🎤 {{__('Show lyrics')}} <input type="checkbox"
+ class="checkbox-switch"
+ name="show_lyrics_{{$song->id}}"
+ data-default="1"></a></li>
+ <li><a href="#" class="noaction">🎼 {{__('Show chords')}} <input type="checkbox"
+ class="checkbox-switch"
+ name="show_chords_{{$song->id}}"
+ data-default="1"></a></li>
@if($song->hasSimpleChords())
<li><a href="#" class="noaction">🐣 {{__('Show simple chords')}} <input type="checkbox"
- class="checkbox-switch"
- name="show_simplechords_{{$song->id}}"
- data-default="0"></a></li>
+ class="checkbox-switch"
+ name="show_simplechords_{{$song->id}}"
+ data-default="0"></a>
+ </li>
@endif
- <li><a href="#" class="clickselect">↕️ {{__('Key')}} <select data-name="tone" name="tone_{{$song->id}}">
+ <li><a href="#" class="clickselect">↕️ {{__('Key')}} <select data-name="tone"
+ name="tone_{{$song->id}}">
@for($i=-5;$i<=6;$i++)
<option value="{{$i}}"
@if($i===0) selected @endif>{{$tones[(12+$song->key+$i)%12].$song->mode}} @if($i>0)
</select><span></span></a></li>
@else
<li class="hidden"><a href="#" class="noaction">{{__('Show chords')}} <input type="checkbox"
- class="checkbox-switch"
- name="show_chords_{{$song->id}}"
- data-default="0"></a></li>
+ class="checkbox-switch"
+ name="show_chords_{{$song->id}}"
+ data-default="0"></a>
+ </li>
<li class="hidden"><a href="#" class="noaction">{{__('Show lyrics')}} <input type="checkbox"
- class="checkbox-switch"
- name="show_lyrics_{{$song->id}}"
- data-default="1"></a></li>
+ class="checkbox-switch"
+ name="show_lyrics_{{$song->id}}"
+ data-default="1"></a>
+ </li>
@endif
<li><a href="#" class="clickselect">🔠 {{__('Lyrics text size')}} <select data-name="size"
- name="size_{{$song->id}}">
+ name="size_{{$song->id}}">
@foreach($fontSizes as $s)
<option value="{{$s}}" @if($s===1) selected @endif>{!! round($s*100) !!}%</option>
@endforeach
@if(count($song->getAudioTracks())>0)
<li><a href="#" class="clickselect">💿 {{__('Audio track')}} <select data-name="audio"
- name="audio_{{$song->id}}">
+ name="audio_{{$song->id}}">
@foreach($song->getAudioTracks() as $i=>$track)
<option value="{{$i}}" data-url="{{$track['url']}}">{{$track['name']}}</option>
@endforeach
@endphp
@extends('layout')
-@section('title', $song->title.' - '.$song->artist.' - '. $collection->name.' Songbook')
+@section('title', $song->title.' - '.$song->artist.' - '. $collection->name)
@section('content')
@include('header',['title'=>$song->title,'subtitle'=>$song->artist])
<article class="song" data-tone="{{$song->key}}" data-mode="{{$song->mode}}">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
- <title>{{$collection->name}} Songbook</title>
+ <title>{{$collection->name}}</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
|
*/
-Route::get('/', function(){
+Route::get('/', function () {
return FrontController::defaultCollection();
});
Route::get('{collection}.webmanifest', [FrontController::class, 'manifest']);
-Route::get('{collection}', [FrontController::class, 'collection']);
-Route::get('{collection}/{song}.html', [FrontController::class, 'song']);
+Route::any('{collection}', [FrontController::class, 'collection']);
+Route::any('{collection}/{song}.html', [FrontController::class, 'song']);