From: Daniel Karbach <daniel.karbach@localhorst.tv>
Date: Sun, 21 Aug 2022 14:19:04 +0000 (+0200)
Subject: technique chapters
X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=7e8555cfc96dcd364ca4fe9895e51af1bb04b546;p=alttp.git

technique chapters
---

diff --git a/app/Http/Controllers/TechniqueController.php b/app/Http/Controllers/TechniqueController.php
index 97a45f0..cce39ce 100644
--- a/app/Http/Controllers/TechniqueController.php
+++ b/app/Http/Controllers/TechniqueController.php
@@ -10,6 +10,7 @@ class TechniqueController extends Controller
 
 	public function single(Request $request, Technique $tech) {
 		$this->authorize('view', $tech);
+		$tech->load('chapters');
 		return $tech->toJson();
 	}
 
diff --git a/app/Models/Technique.php b/app/Models/Technique.php
index 2caa5f3..1a54a0e 100644
--- a/app/Models/Technique.php
+++ b/app/Models/Technique.php
@@ -9,6 +9,14 @@ class Technique extends Model
 {
 	use HasFactory;
 
+	public function chapters() {
+		return $this
+			->belongsToMany(Technique::class, 'technique_chapter', 'parent_id', 'child_id')
+			->withPivot('level', 'order')
+			->orderByPivot('order')
+			->using(TechniqueChapter::class);
+	}
+
 	protected $casts = [
 		'index' => 'boolean',
 	];
diff --git a/app/Models/TechniqueChapter.php b/app/Models/TechniqueChapter.php
new file mode 100644
index 0000000..fda4fbd
--- /dev/null
+++ b/app/Models/TechniqueChapter.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Relations\Pivot;
+
+class TechniqueChapter extends Pivot
+{
+	//
+}
diff --git a/database/migrations/2022_08_21_130547_create_technique_chapter_table.php b/database/migrations/2022_08_21_130547_create_technique_chapter_table.php
new file mode 100644
index 0000000..339ac77
--- /dev/null
+++ b/database/migrations/2022_08_21_130547_create_technique_chapter_table.php
@@ -0,0 +1,38 @@
+<?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('techniques', function (Blueprint $table) {
+			$table->string('name')->nullable()->default(null)->change();
+		});
+		Schema::create('technique_chapter', function (Blueprint $table) {
+			$table->id();
+			$table->foreignId('parent_id')->references('id')->on('techniques')->constrained();
+			$table->foreignId('child_id')->references('id')->on('techniques')->constrained();
+			$table->integer('level')->default(2);
+			$table->integer('order')->default(0);
+			$table->timestamps();
+		});
+	}
+
+	/**
+	 * Reverse the migrations.
+	 *
+	 * @return void
+	 */
+	public function down()
+	{
+		Schema::dropIfExists('technique_chapter');
+	}
+};
diff --git a/resources/js/components/techniques/Detail.js b/resources/js/components/techniques/Detail.js
index 88ce594..d586a9a 100644
--- a/resources/js/components/techniques/Detail.js
+++ b/resources/js/components/techniques/Detail.js
@@ -2,13 +2,26 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import { Container } from 'react-bootstrap';
 
-const Detail = ({ technique }) => <Container>
+import Outline from './Outline';
+
+const Detail = ({ technique }) => <Container as="article">
 	<h1>{technique.title}</h1>
+	<Outline technique={technique} />
 	<div dangerouslySetInnerHTML={{ __html: technique.description }} />
+	{technique.chapters ? technique.chapters.map(chapter =>
+		<section id={`c${chapter.id}`} key={`c${chapter.id}`}>
+			{chapter.pivot.level ?
+				React.createElement(`h${chapter.pivot.level}`, {}, chapter.title)
+			: null}
+			<div dangerouslySetInnerHTML={{ __html: chapter.description }} />
+		</section>
+	) : null}
 </Container>;
 
 Detail.propTypes = {
 	technique: PropTypes.shape({
+		chapters: PropTypes.arrayOf(PropTypes.shape({
+		})),
 		description: PropTypes.string,
 		title: PropTypes.string,
 	}),
diff --git a/resources/js/components/techniques/Outline.js b/resources/js/components/techniques/Outline.js
new file mode 100644
index 0000000..bf98eba
--- /dev/null
+++ b/resources/js/components/techniques/Outline.js
@@ -0,0 +1,29 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { ListGroup } from 'react-bootstrap';
+
+const Outline = ({ technique }) => technique.chapters && technique.chapters.length ?
+	<aside className="tech-outline mb-3 ms-3">
+		<ListGroup>
+			{technique.chapters.map(chapter => chapter.pivot.level ?
+				<ListGroup.Item
+					action
+					href={`#c${chapter.id}`}
+					key={`c${chapter.id}`}
+					title={chapter.short || null}
+				>
+					{chapter.title}
+				</ListGroup.Item>
+			: null)}
+		</ListGroup>
+	</aside>
+: null;
+
+Outline.propTypes = {
+	technique: PropTypes.shape({
+		chapters: PropTypes.arrayOf(PropTypes.shape({
+		})),
+	}),
+};
+
+export default Outline;
diff --git a/resources/sass/app.scss b/resources/sass/app.scss
index 2ba2635..64f81df 100644
--- a/resources/sass/app.scss
+++ b/resources/sass/app.scss
@@ -17,5 +17,6 @@
 @import 'participants';
 @import 'results';
 @import 'rounds';
+@import 'techniques';
 @import 'tournaments';
 @import 'users';
diff --git a/resources/sass/techniques.scss b/resources/sass/techniques.scss
new file mode 100644
index 0000000..c4fa505
--- /dev/null
+++ b/resources/sass/techniques.scss
@@ -0,0 +1,3 @@
+.tech-outline {
+	float: right;
+}