feat: reader v1 functionally complete

This commit is contained in:
Jonathan Nielson 2025-10-11 15:29:03 -05:00
parent 0e3902d16b
commit 53740b8ad3
11 changed files with 230 additions and 21 deletions

View File

@ -25,3 +25,7 @@ MAIL_PASSWORD=null
MAIL_ENCRYPTION=null MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}" MAIL_FROM_NAME="${APP_NAME}"
PUBLISHING_NAME="Word Salad"
SUBHEAD="A blog with an as yet unclear direction."
CONTACT_EMAIL="test@example.org"

View File

@ -11,7 +11,7 @@ return [
| |
*/ */
'publishing_name' => 'Jon\'s Words', 'publishing_name' => env('PUBLISHING_NAME', 'Word Salad'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -22,6 +22,17 @@ return [
| |
*/ */
'subheading' => 'A blog with an as yet unclear direction.', 'subheading' => env('SUBHEAD', 'A blog with an as yet unclear direction.'),
/*
|--------------------------------------------------------------------------
| Contact Email
|--------------------------------------------------------------------------
|
| The public-facing email displayed in general contact and support areas of the blog
|
*/
'contact_email' => env('CONTACT_EMAIL', 'test@example.org'),
]; ];

View File

@ -1,2 +1,68 @@
User-agent: * # Block all known AI crawlers and assistants
Disallow: # from using content for training AI models.
# Source: https://robotstxt.com/ai
User-Agent: GPTBot
User-Agent: ClaudeBot
User-Agent: Claude-User
User-Agent: Claude-SearchBot
User-Agent: CCBot
User-Agent: Google-Extended
User-Agent: Applebot-Extended
User-Agent: Facebookbot
User-Agent: Meta-ExternalAgent
User-Agent: Meta-ExternalFetcher
User-Agent: diffbot
User-Agent: PerplexityBot
User-Agent: PerplexityUser
User-Agent: Omgili
User-Agent: Omgilibot
User-Agent: webzio-extended
User-Agent: ImagesiftBot
User-Agent: Bytespider
User-Agent: TikTokSpider
User-Agent: Amazonbot
User-Agent: Youbot
User-Agent: SemrushBot-OCOB
User-Agent: Petalbot
User-Agent: VelenPublicWebCrawler
User-Agent: TurnitinBot
User-Agent: Timpibot
User-Agent: OAI-SearchBot
User-Agent: ICC-Crawler
User-Agent: AI2Bot
User-Agent: AI2Bot-Dolma
User-Agent: DataForSeoBot
User-Agent: AwarioBot
User-Agent: AwarioSmartBot
User-Agent: AwarioRssBot
User-Agent: Google-CloudVertexBot
User-Agent: PanguBot
User-Agent: Kangaroo Bot
User-Agent: Sentibot
User-Agent: img2dataset
User-Agent: Meltwater
User-Agent: Seekr
User-Agent: peer39_crawler
User-Agent: cohere-ai
User-Agent: cohere-training-data-crawler
User-Agent: DuckAssistBot
User-Agent: Scrapy
User-Agent: Cotoyogi
User-Agent: aiHitBot
User-Agent: Factset_spyderbot
User-Agent: FirecrawlAgent
Disallow: /
DisallowAITraining: /
# Block any non-specified AI crawlers (e.g., new
# or unknown bots) from using content for training
# AI models, while allowing the website to be
# indexed and accessed by bots. These directives
# are still experimental and may not be supported
# by all AI crawlers.
User-Agent: *
DisallowAITraining: /
Content-Usage: ai=n
Allow: /

View File

@ -4,7 +4,13 @@
body { body {
/* background-color: #813d9c; /* Old Purple */ /* background-color: #813d9c; /* Old Purple */
background-color: #2d033e; /* New Purple */ /* background-color: #2d033e; /* New Solid Purple */
/*
* Created with https://www.css-gradient.com
* Gradient link: https://www.css-gradient.com/?c1=550b73&c2=2e033e&gt=r&gd=dcl
*/
background: #550B73;
background: radial-gradient(at left center, #550B73, #2E033E);
color: white; color: white;
text-shadow: 1px 1px 2px blueviolet; text-shadow: 1px 1px 2px blueviolet;
margin: 0; margin: 0;
@ -15,6 +21,16 @@ main {
justify-content: center; justify-content: center;
} }
main a {
color: #ff9344;
text-decoration: none;
}
main a:hover {
text-decoration: aliceblue;
text-decoration-line: underline;
}
article { article {
max-width: 60vw; max-width: 60vw;
} }
@ -23,6 +39,17 @@ article {
article { article {
max-width: 90vw; max-width: 90vw;
} }
main {
flex-direction: column;
padding: 0 1.25em;
}
}
@media screen and (min-width: 1250px) {
#recent-articles-list {
margin-left: 3em;
}
} }
a { a {
@ -45,16 +72,19 @@ nav {
justify-content: space-between; justify-content: space-between;
} }
#nav-logo {
padding: 1em;
}
#nav-logo > a { #nav-logo > a {
text-decoration: none; text-decoration: none;
color: #ff9344; color: #ff9344;
font-size: x-large; font-size: xx-large;
font-weight: bold; font-weight: bold;
margin: 0.3em;
} }
#article-header-separator { #article-header-separator {
width: 60%; width: 70%;
color: white; color: white;
margin: 2em auto; margin: 2em auto;
} }
@ -64,10 +94,12 @@ footer {
min-height: 7em; min-height: 7em;
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-direction: column;
align-items: center;
} }
#subscribe-form { #subscribe-form {
border-radius: 1.5em; border-radius: 0.5em;
border-color: white; border-color: white;
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
@ -87,9 +119,64 @@ footer {
flex-direction: column; flex-direction: column;
} }
#subscribe-form input {
padding: 0.5em;
}
#subscribe-button { #subscribe-button {
background-color: #ff9344; background-color: #ff9344;
color: white; color: white;
font-weight: bold;
border-radius: 0.5em;
cursor: pointer;
}
#blog-head {
display: flex;
flex-direction: column;
justify-content: center;
align-items: end;
margin: 0.5em;
}
#blog-head h1 {
font-size: 2.6em;
}
#blog-head h2 {
margin-top: 0;
}
.article-peek dl {
display: flex;
gap: 0.5em;
align-items: baseline;
}
.article-peek dd {
margin: 0 2em 0 0.25em;
}
.article-peek dt {
font-size: small;
font-weight: lighter;
}
#recent-articles-list {
padding: 0 1em;
}
#recent-articles-list h3 {
margin-bottom: 0.75em;
font-size: 120%;
}
#recent-articles-list h4 {
margin: 0.25em 0;
}
#recent-articles-list article {
margin-bottom: 2.5em;
} }
/* .bubble-panel { /* .bubble-panel {
@ -99,3 +186,34 @@ footer {
33px -33px 65px #9c4abd; 33px -33px 65px #9c4abd;
padding: 2em; padding: 2em;
}*/ }*/
/* Create a custom animation */
@keyframes move-out {
from {
transform: translateY(0%);
}
to {
transform: translateY(-100%);
}
}
@keyframes move-in {
from {
transform: translateY(100%);
}
to {
transform: translateY(0%);
}
}
/* Apply the custom animation to the old and new page states */
::view-transition-old(root) {
animation: 0.4s ease-in both move-out;
}
::view-transition-new(root) {
animation: 0.4s ease-in both move-in;
}

View File

@ -4,13 +4,13 @@
@section('content') @section('content')
<section id="blog-head" class="bubble-panel"> <section id="blog-head" class="bubble-panel">
<h1>{{ config('blog.publishing_name') }}<h1> <h1>{{ config('blog.publishing_name') }}</h1>
<p><i>{{ config('blog.subheading') }}</i></p> <h2><i>{{ config('blog.subheading') }}</i></h2>
</section> </section>
<section> <section id="recent-articles-list">
@if(count($articles) > 0) @if(count($articles) > 0)
@foreach($articles as $article) @foreach($articles as $article)
<article> <article class="article-peek">
<h3> <h3>
<a href="{{ route('article', ['article_slug' => $article->slug]) }}"> <a href="{{ route('article', ['article_slug' => $article->slug]) }}">
{{ $article->title }} {{ $article->title }}
@ -19,6 +19,13 @@
<h4> <h4>
{{ $article->subtitle }} {{ $article->subtitle }}
</h4> </h4>
<dl>
<dt>Author:</dt>
<dd>{{ $article->author->display_name }}</dd>
<dt>Published:</dt>
<dd>{{ $article->published_at }}</dd>
</dl>
</article> </article>
@endforeach @endforeach
{{-- {{--

View File

@ -1,5 +1,5 @@
<nav id="main-nav"> <nav id="main-nav">
<div id="nav-logo"><a href="/">{{ config('app.name') }}</a></div> <div id="nav-logo"><a href="/">{{ config('blog.publishing_name') }}</a></div>
<div> <div>
{{-- {{--
<form action="{{route('search')}}"> <form action="{{route('search')}}">

View File

@ -5,6 +5,6 @@
@section('content') @section('content')
<section> <section>
<h1>Subscription Error</h1> <h1>Subscription Error</h1>
<p>Something went wrong while marking your interest. Sorry.</p> <p>Something went wrong while marking your interest. Please try again, or contact me at {{ config('blog.contact_email') }} if the problem persists.</p>
</section> </section>
@endsection @endsection

View File

@ -5,6 +5,6 @@
@section('content') @section('content')
<section> <section>
<h1>Subscription Confirmed</h1> <h1>Subscription Confirmed</h1>
<p>You'll be the first to know about future posts. Thank you.</p> <p>Thank you! You'll be the first to know about future posts.</p>
</section> </section>
@endsection @endsection

View File

@ -1,3 +1,3 @@
<section id="top-bar"> <section id="top-bar">
UNRWA is working tirelessly to alleviate the horrors of genocide in Gaza.&nbsp;<a href="https://www.unrwausa.org/donate">Support them here</a>&nbsp;🇵🇸 UNRWA is working tirelessly to alleviate the horrors of genocide in Gaza.&nbsp;<a href="https://www.unrwausa.org/donate" target="_blank">Support them here</a>&nbsp;🇵🇸
</section> </section>

View File

@ -25,9 +25,12 @@
@yield('content', 'Nothing to see here.') @yield('content', 'Nothing to see here.')
</main> </main>
</body> </body>
@if(! in_array(Route::currentRouteName(), ['subscribe-success', 'subscribe-fail']))
<footer> <footer>
@if(! in_array(Route::currentRouteName(), ['subscribe-success', 'subscribe-fail']))
@include('shared.subscribe-form') @include('shared.subscribe-form')
</footer>
@endif @endif
<div id="footer-copyright">
&#169; {{ (new DateTime())->format('Y') }}
</div>
</footer>
</html> </html>

View File

@ -18,7 +18,7 @@ use Illuminate\Support\Facades\Route;
*/ */
Route::get('/', function () { Route::get('/', function () {
$articles = Article::where('published_at', '<', now())->latest()->limit(10)->get(); $articles = Article::with(['author'])->where('published_at', '<', now())->latest()->limit(5)->get();
return view('guest.home', ['articles' => $articles]); return view('guest.home', ['articles' => $articles]);
}); });