Feat: Get basic live-preview article working with HTMX

This commit is contained in:
Jonathan Nielson 2024-08-16 17:46:59 -05:00
parent a63063acf7
commit 89ce206d23
5 changed files with 91 additions and 27 deletions

View File

@ -52,25 +52,27 @@ class WriterController extends Controller
public function livePreview(Request $request): View public function livePreview(Request $request): View
{ {
// Upload the file // Upload the file
$header_image_path = $request->headerImage->storeAs('header-image-previews'); logger('hey', ['stuff' => request()->all()]);
sleep(2);
$header_image_path = $request->headerImage?->storeAs('header-image-previews');
$article_empty = new Article(); $article_empty = new Article();
$article_empty->markdown_body = $request->markdownBody; $article_empty->markdown_body = $request->get('markdown-body');
$article_empty->generateMarkupFromMarkdown(); $article_empty->convertMarkdownToMarkup();
$article = [ $article = [
'title' => $request->title ?? null, 'title' => $request->title ?? null,
'header_image_url' => $header_image_path ?? null, 'header_image_url' => $header_image_path ?? null,
'subtitle' => $request->subtitle ?? null, 'subtitle' => $request->subtitle ?? null,
'author' => [ 'author' => [
'display_name' => auth()->user()->author->displayName, 'display_name' => auth()->user()->author?->displayName,
], ],
'published_at' => $request->publicationDate ?? null, 'published_at' => $request->get('publication-date') ?? null,
'primary_link' => $request->primary_link ?? null, 'primary_link' => $request->primary_link ?? null,
'secondary_link' => $request->secondary_link ?? null, 'secondary_link' => $request->secondary_link ?? null,
'mastodon_handle' => $request->mastodon_handle ?? null, 'mastodon_handle' => $request->mastodon_handle ?? null,
'body' => $article_empty->body, 'body' => $article_empty->body,
]; ];
return view('guest.article', ['article' => $article]); return view('shared.single-article', ['article' => $article]);
} }
} }

View File

@ -3,20 +3,7 @@
@section('title', $article['title']) @section('title', $article['title'])
@section('content') @section('content')
<article>
<a href="{{ url()->previous() }}">&nbsp;&nbsp;&larr;&nbsp;Go Back</a> @include('shared.single-article')
<img src="{{ $article['header_image_url'] }}" />
<h1>{{ $article['title'] }}</h1>
<h2>{{ $article['subtitle'] }}</h2>
<p>{{ $article['author']['display_name'] }}</p>
<p>Published At: {{ $article['published_at'] }}</p>
<ul>
<li><a href="{{ $article['primary_link'] }}">Link 1</a></li>
<li><a href="{{ $article['secondary_link'] }}">Link 2</a></li>
<li><a href="{{ $article['mastodon_handle'] }}">Mastodon</a></li>
</ul>
<main>
{!! $article['body'] !!}
</main>
</article>
@endsection @endsection

View File

@ -10,6 +10,12 @@
{{-- Include HTMX on the writer-side to enchance our interactivity --}} {{-- Include HTMX on the writer-side to enchance our interactivity --}}
<script src="/htmx.1.9.12.js"></script> <script src="/htmx.1.9.12.js"></script>
<script>
htmx.on("htmx:configRequest", (e)=> {
e.detail.headers["X-CSRF-TOKEN"] = '{{ csrf_token() }}';
})
</script>
<title>{{ config('blog.publishing_name') }} | @yield('title')</title> <title>{{ config('blog.publishing_name') }} | @yield('title')</title>
</head> </head>
<body> <body>

View File

@ -0,0 +1,16 @@
<article>
<a href="{{ url()->previous() }}">&nbsp;&nbsp;&larr;&nbsp;Go Back</a>
<img src="{{ $article['header_image_url'] }}" />
<h1>{{ $article['title'] }}</h1>
<h2>{{ $article['subtitle'] }}</h2>
<p>{{ $article['author']['display_name'] }}</p>
<p>Published At: {{ $article['published_at'] }}</p>
<ul>
<li><a href="{{ $article['primary_link'] }}">Link 1</a></li>
<li><a href="{{ $article['secondary_link'] }}">Link 2</a></li>
<li><a href="{{ $article['mastodon_handle'] }}">Mastodon</a></li>
</ul>
<main>
{!! $article['body'] !!}
</main>
</article>

View File

@ -18,16 +18,63 @@
#markdown-body { #markdown-body {
width: 40vw; width: 40vw;
} }
/* HTML: <div class="loader"></div> */
.loader {
width: 45px;
height: 30px;
background:
linear-gradient(#004ce4 0 0) 0 100%/100% 50%,
linear-gradient(#004ce4 0 0) 0 0 /calc(100%/3) 100%;
background-repeat: no-repeat;
position: relative;
clip-path: inset(-100% 0 0 0);
animation: l2-0 2s infinite steps(4);
}
.loader::before,
.loader::after {
content: "";
position: absolute;
inset:-50% 0 50%;
background:
linear-gradient(#00e622 0 0) 0 0 /calc(2*100%/3) 50%,
linear-gradient(#00e622 0 0) 100% 100%/calc(2*100%/3) 50%;
background-repeat: no-repeat;
animation: inherit;
animation-name: l2-1;
}
.loader::after {
inset:-100% 0 100%;
background:
linear-gradient(#e50021 0 0) 0 0/100% 50%,
linear-gradient(#e50021 0 0) 100% 0/calc(100%/3) 100%;
background-repeat: no-repeat;
animation-name: l2-2;
}
@keyframes l2-0{
0% {transform: translateY(-250%);clip-path: inset(100% 0 0 0)}
25%,100% {transform: translateY(0);clip-path: inset(-100% 0 0 0)}
}
@keyframes l2-1{
0% ,25% {transform: translateY(-250%)}
50%,100% {transform: translateY(0)}
}
@keyframes l2-2{
0% ,50% {transform: translateY(-250%)}
75%,100% {transform: translateY(0)}
}
</style> </style>
<script> <script>
document.addEventListener("DOMContentLoaded", (event) => { document.addEventListener("DOMContentLoaded", (event) => {
document.getElementById('preview-article').style.display = 'none';
document.getElementById('htmx-preview-button').style.display = 'none';
}); });
</script> </script>
<div id="page-body-container"> <div id="page-body-container">
<section id="new-article-form-container"> <section id="new-article-form-container">
<form id="new-article-form" method="POST" action="route('')"> <form id="new-article-form" method="POST" action="route('live_preview')">
<label for="publication-date">Publication Date</label> <label for="publication-date">Publication Date</label>
<input id="publication-date" name="publication-date" type="datetime-local" class="affects-preview" /> <input id="publication-date" name="publication-date" type="datetime-local" class="affects-preview" />
<label for="title">Title</label> <label for="title">Title</label>
@ -47,23 +94,29 @@ document.addEventListener("DOMContentLoaded", (event) => {
Preview Preview
</button> </button>
<button id="save-article" type="submit">Save</button> <button id="save-article" type="submit">Save</button>
</form>
<button <button
id="htmx-preview-button"
data-hx-post="{{ route('live_preview') }}" data-hx-post="{{ route('live_preview') }}"
data-hx-trigger="click delay:2s" data-hx-trigger="click, keyup changed delay:1500ms from:.affects-preview"
data-hx-target="#true-container" data-hx-target="#true-container"
data-hx-swap="innerHTML" data-hx-swap="innerHTML"
data-hx-indicator="#preview-indicator"
> >
HTMX Preview HTMX Preview
</button> </button>
</form>
</section> </section>
<section id="new-article-preview-container"> <section id="new-article-preview-container">
<h4>Enjoy a live(ish) preview of what your article will look like</h4> <span>Live Preview</span>
<span id="preview-indicator" class="htmx-indicator"><div class="loader"></div></span>
<div class="checkmark"></div>
<div id="preview-inner-container"> <div id="preview-inner-container">
@if(isset($article_preview)) @if(isset($article_preview))
<div id="true-container"></div> <div id="true-container"></div>
@else @else
<p>Nothing to see yet!</p> <div id="true-container">
<p>Nothing to see yet!</p>
</div>
@endif @endif
</div> </div>
</section> </section>