news module added

This commit is contained in:
Benjamin Takats
2023-01-20 14:55:08 +01:00
parent 02eb2babd7
commit ad3b58b19d
27 changed files with 479 additions and 32 deletions

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Console\Commands\Database;
use App\Models\LibraryItem;
use Illuminate\Console\Command;
class MigrateLibraryItemSlugs extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'library_items:slugs';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
foreach (LibraryItem::all() as $item) {
$item->slug = str($item->name)->slug('-', 'de');
$item->save();
}
return Command::SUCCESS;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Livewire\News;
use App\Models\LibraryItem;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class ArticleOverview extends Component
{
public function render()
{
return view('livewire.news.article-overview', [
'libraryItems' => LibraryItem::query()
->with([
'createdBy.roles',
'lecturer',
'tags',
])
->where('type', 'markdown_article')
->whereHas('createdBy.roles',
fn($query) => $query->where('roles.name', 'news-editor'))
->get(),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('News'),
description: __('Here we post important news that is relevant for everyone.'),
image: asset('img/einundzwanzig-wallpaper-benrath.png'),
)
]);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Http\Livewire\News;
use App\Models\LibraryItem;
use Carbon\Carbon;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class InternArticleView extends Component
{
public LibraryItem $libraryItem;
public function render()
{
return view('livewire.news.intern-article-view')->layout('layouts.app', [
'SEOData' => new SEOData(
title: $this->libraryItem->name,
description: $this->libraryItem->excerpt ?? __('Here we post important news that is relevant for everyone.'),
author: $this->libraryItem->lecturer->name,
image: asset('img/einundzwanzig-wallpaper-benrath.png'),
published_time: Carbon::parse($this->libraryItem->created_at),
type: 'article',
)
]);
}
}

View File

@@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Cookie;
use Spatie\Sluggable\HasSlug; use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions; use Spatie\Sluggable\SlugOptions;
@@ -48,7 +49,7 @@ class City extends Model
return SlugOptions::create() return SlugOptions::create()
->generateSlugsFrom(['country.code', 'name']) ->generateSlugsFrom(['country.code', 'name'])
->saveSlugsTo('slug') ->saveSlugsTo('slug')
->usingLanguage('de'); ->usingLanguage(Cookie::get('lang', config('app.locale')));
} }
public function createdBy(): BelongsTo public function createdBy(): BelongsTo

View File

@@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Support\Facades\Cookie;
use Spatie\Image\Manipulations; use Spatie\Image\Manipulations;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\InteractsWithMedia;
@@ -76,7 +77,7 @@ class Lecturer extends Model implements HasMedia
return SlugOptions::create() return SlugOptions::create()
->generateSlugsFrom(['name']) ->generateSlugsFrom(['name'])
->saveSlugsTo('slug') ->saveSlugsTo('slug')
->usingLanguage('de'); ->usingLanguage(Cookie::get('lang', config('app.locale')));
} }
public function createdBy(): BelongsTo public function createdBy(): BelongsTo

View File

@@ -5,6 +5,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Facades\Cookie;
use Spatie\EloquentSortable\Sortable; use Spatie\EloquentSortable\Sortable;
use Spatie\EloquentSortable\SortableTrait; use Spatie\EloquentSortable\SortableTrait;
use Spatie\Image\Manipulations; use Spatie\Image\Manipulations;
@@ -12,6 +13,8 @@ use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media; use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\ModelStatus\HasStatuses; use Spatie\ModelStatus\HasStatuses;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
use Spatie\Tags\HasTags; use Spatie\Tags\HasTags;
class LibraryItem extends Model implements HasMedia, Sortable class LibraryItem extends Model implements HasMedia, Sortable
@@ -20,6 +23,7 @@ class LibraryItem extends Model implements HasMedia, Sortable
use HasTags; use HasTags;
use SortableTrait; use SortableTrait;
use HasStatuses; use HasStatuses;
use HasSlug;
/** /**
* The attributes that aren't mass assignable. * The attributes that aren't mass assignable.
@@ -37,6 +41,14 @@ class LibraryItem extends Model implements HasMedia, Sortable
'library_id' => 'integer', 'library_id' => 'integer',
]; ];
public function getSlugOptions(): SlugOptions
{
return SlugOptions::create()
->generateSlugsFrom(['name'])
->saveSlugsTo('slug')
->usingLanguage(Cookie::get('lang', config('app.locale')));
}
protected static function booted() protected static function booted()
{ {
static::creating(function ($model) { static::creating(function ($model) {

View File

@@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Cookie;
use Spatie\Image\Manipulations; use Spatie\Image\Manipulations;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\InteractsWithMedia;
@@ -48,7 +49,7 @@ class Meetup extends Model implements HasMedia
return SlugOptions::create() return SlugOptions::create()
->generateSlugsFrom(['name']) ->generateSlugsFrom(['name'])
->saveSlugsTo('slug') ->saveSlugsTo('slug')
->usingLanguage('de'); ->usingLanguage(Cookie::get('lang', config('app.locale')));
} }
public function registerMediaConversions(Media $media = null): void public function registerMediaConversions(Media $media = null): void

View File

@@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Cookie;
use Spatie\Image\Manipulations; use Spatie\Image\Manipulations;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\InteractsWithMedia;
@@ -71,7 +72,7 @@ class Venue extends Model implements HasMedia
return SlugOptions::create() return SlugOptions::create()
->generateSlugsFrom(['city.slug', 'name',]) ->generateSlugsFrom(['city.slug', 'name',])
->saveSlugsTo('slug') ->saveSlugsTo('slug')
->usingLanguage('de'); ->usingLanguage(Cookie::get('lang', config('app.locale')));
} }
public function createdBy(): BelongsTo public function createdBy(): BelongsTo

View File

@@ -13,6 +13,7 @@ use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\BelongsToMany; use Laravel\Nova\Fields\BelongsToMany;
use Laravel\Nova\Fields\Code; use Laravel\Nova\Fields\Code;
use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Number;
use Laravel\Nova\Fields\Select; use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\Text; use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest; use Laravel\Nova\Http\Requests\NovaRequest;
@@ -112,7 +113,8 @@ class LibraryItem extends Resource
->options( ->options(
config('languages.languages') config('languages.languages')
) )
->rules('required', 'string')->searchable(), ->rules('required', 'string')
->searchable(),
Tags::make('Tags') Tags::make('Tags')
->type('library_item') ->type('library_item')
@@ -121,6 +123,19 @@ class LibraryItem extends Resource
Text::make('Name') Text::make('Name')
->rules('required', 'string'), ->rules('required', 'string'),
Text::make(__('Subtitle'), 'subtitle')
->rules('nullable', 'string'),
Text::make(__('Excerpt'), 'excerpt')
->rules('nullable', 'string')->help(__('This is the excerpt that is shown in the overview.')),
Text::make(__('Main image caption'), 'main_image_caption')
->rules('nullable', 'string'),
Number::make(__('Time to read'), 'read_time')
->rules('nullable', 'numeric')
->help(__('How many minutes to read?')),
Select::make(__('Type'), 'type') Select::make(__('Type'), 'type')
->options( ->options(
Options::forEnum(LibraryItemType::class) Options::forEnum(LibraryItemType::class)
@@ -132,7 +147,9 @@ class LibraryItem extends Resource
->rules('nullable', 'string') ->rules('nullable', 'string')
->help('Please paste the URL to the video here, or the link to the blog article, or the link to the book, or the Markdown itself.'), ->help('Please paste the URL to the video here, or the link to the blog article, or the link to the book, or the Markdown itself.'),
BelongsTo::make(__('Lecturer/Content Creator'), 'lecturer', Lecturer::class)->searchable()->withSubtitles(), BelongsTo::make(__('Lecturer/Content Creator'), 'lecturer', Lecturer::class)
->searchable()
->withSubtitles(),
BelongsTo::make(__('Episode'), 'episode', Episode::class) BelongsTo::make(__('Episode'), 'episode', Episode::class)
->nullable() ->nullable()
@@ -145,7 +162,8 @@ class LibraryItem extends Resource
return $request->user() return $request->user()
->hasRole('super-admin'); ->hasRole('super-admin');
}) })
->searchable()->withSubtitles(), ->searchable()
->withSubtitles(),
]; ];
} }

View File

@@ -0,0 +1,32 @@
<?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('library_items', function (Blueprint $table) {
$table->string('slug')
->unique()
->nullable()
->after('id');
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::table('library_items', function (Blueprint $table) {
//
});
}
};

View File

@@ -0,0 +1,36 @@
<?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('library_items', function (Blueprint $table) {
$table->text('subtitle')
->nullable();
$table->text('excerpt')
->nullable();
$table->string('main_image_caption')
->nullable();
$table->string('read_time')
->nullable();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::table('library_items', function (Blueprint $table) {
//
});
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

View File

@@ -672,5 +672,15 @@
"PlebChat": "", "PlebChat": "",
"Close panel": "Schließe Panel", "Close panel": "Schließe Panel",
"This chat is limited by 21 messages.": "Dieser Chat ist auf 21 Nachrichten begrenzt. Die ältesten Nachrichten werden gelöscht und die Nachrichten werden nicht gespeichert. (nur im RAM des Servers)", "This chat is limited by 21 messages.": "Dieser Chat ist auf 21 Nachrichten begrenzt. Die ältesten Nachrichten werden gelöscht und die Nachrichten werden nicht gespeichert. (nur im RAM des Servers)",
"Send": "Senden" "Send": "Senden",
} "Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
}

View File

@@ -666,5 +666,15 @@
"PlebChat": "", "PlebChat": "",
"Close panel": "", "Close panel": "",
"This chat is limited by 21 messages.": "", "This chat is limited by 21 messages.": "",
"Send": "" "Send": "",
} "Main image caption": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
}

View File

@@ -659,5 +659,22 @@
"Lightning Address": "", "Lightning Address": "",
"LNURL": "", "LNURL": "",
"Node Id": "", "Node Id": "",
"Scan this code or copy & paste it to your lightning wallet. Or click to login with your wallet.": "" "Scan this code or copy & paste it to your lightning wallet. Or click to login with your wallet.": "",
} "Parent": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"PlebChat": "",
"Close panel": "",
"This chat is limited by 21 messages.": "",
"Send": "",
"News": "",
"Entries": "",
"Dezentral News": "",
"min read": "",
"Payment Required": "",
"Here we post important news that is relevant for everyone.": ""
}

View File

@@ -667,5 +667,15 @@
"Close panel": "", "Close panel": "",
"This chat is limited by 100 messages.": "", "This chat is limited by 100 messages.": "",
"Send": "", "Send": "",
"This chat is limited by 21 messages.": "" "This chat is limited by 21 messages.": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
} }

View File

@@ -667,5 +667,15 @@
"Close panel": "", "Close panel": "",
"This chat is limited by 100 messages.": "", "This chat is limited by 100 messages.": "",
"Send": "", "Send": "",
"This chat is limited by 21 messages.": "" "This chat is limited by 21 messages.": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
} }

View File

@@ -667,5 +667,15 @@
"Close panel": "", "Close panel": "",
"This chat is limited by 100 messages.": "", "This chat is limited by 100 messages.": "",
"Send": "", "Send": "",
"This chat is limited by 21 messages.": "" "This chat is limited by 21 messages.": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
} }

View File

@@ -667,5 +667,15 @@
"Close panel": "", "Close panel": "",
"This chat is limited by 100 messages.": "", "This chat is limited by 100 messages.": "",
"Send": "", "Send": "",
"This chat is limited by 21 messages.": "" "This chat is limited by 21 messages.": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
} }

View File

@@ -667,5 +667,15 @@
"Close panel": "", "Close panel": "",
"This chat is limited by 100 messages.": "", "This chat is limited by 100 messages.": "",
"Send": "", "Send": "",
"This chat is limited by 21 messages.": "" "This chat is limited by 21 messages.": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
} }

View File

@@ -667,5 +667,15 @@
"Close panel": "", "Close panel": "",
"This chat is limited by 100 messages.": "", "This chat is limited by 100 messages.": "",
"Send": "", "Send": "",
"This chat is limited by 21 messages.": "" "This chat is limited by 21 messages.": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
} }

View File

@@ -641,5 +641,15 @@
"Close panel": "", "Close panel": "",
"This chat is limited by 100 messages.": "", "This chat is limited by 100 messages.": "",
"Send": "", "Send": "",
"This chat is limited by 21 messages.": "" "This chat is limited by 21 messages.": "",
"Excerpt": "",
"This is the excerpt that is shown in the overview.": "",
"Main image caption": "",
"Time to read": "",
"How many minutes to read?": "",
"Read": "",
"News": "",
"Dezentral News": "",
"min read": "",
"Here we post important news that is relevant for everyone.": ""
} }

View File

@@ -17,14 +17,32 @@
{{ __('Listen') }} {{ __('Listen') }}
</x-button> </x-button>
@endif @endif
@if($row->type === 'markdown_article')
<x-button xs amber :href="route('article.view', [$row])">
<i class="fa fa-thin fa-newspaper mr-2"></i>
{{ __('Read') }}
</x-button>
@endif
<x-button @if($row->type !== 'markdown_article')
x-data="{ <x-button
x-data="{
textToCopy: '{{ url()->route('library.table.libraryItems', ['country' => 'de', 'table' => ['filters' => ['id' => $row->id]]]) }}', textToCopy: '{{ url()->route('library.table.libraryItems', ['country' => 'de', 'table' => ['filters' => ['id' => $row->id]]]) }}',
}" }"
@click.prevent="window.navigator.clipboard.writeText(textToCopy);window.$wireui.notify({title:'{{ __('Share url copied!') }}',icon:'success'});" @click.prevent="window.navigator.clipboard.writeText(textToCopy);window.$wireui.notify({title:'{{ __('Share url copied!') }}',icon:'success'});"
xs black> xs black>
<i class="fa fa-thin fa-copy mr-2"></i> <i class="fa fa-thin fa-copy mr-2"></i>
{{ __('Share link') }} {{ __('Share link') }}
</x-button> </x-button>
@else
<x-button
x-data="{
textToCopy: '{{ url()->route('library.table.libraryItems', ['country' => 'de', 'table' => ['filters' => ['id' => $row->id]]]) }}',
}"
@click.prevent="window.navigator.clipboard.writeText(textToCopy);window.$wireui.notify({title:'{{ __('Share url copied!') }}',icon:'success'});"
xs black>
<i class="fa fa-thin fa-copy mr-2"></i>
{{ __('Share link') }}
</x-button>
@endif
</div> </div>

View File

@@ -137,7 +137,7 @@
</div> </div>
<div <div
class="row-span-2 col-span-full sm:col-span-1 md:col-start-3 xl:col-start-4 sm:row-start-5 md:row-start-3 xl:row-start-2"> class="row-span-2 col-span-full sm:col-span-1 md:col-start-3 xl:col-start-4 sm:row-start-5 md:row-start-3 xl:row-start-2">
<a target="_blank" href="https://www.plebrap.space/" <a href="{{ route('article.overview') }}"
class="relative flex flex-col items-start justify-end w-full h-full overflow-hidden bg-black shadow-lg rounded-xl group" class="relative flex flex-col items-start justify-end w-full h-full overflow-hidden bg-black shadow-lg rounded-xl group"
style="aspect-ratio: 1/1;"> style="aspect-ratio: 1/1;">
<div class="absolute inset-0 w-full h-full"> <div class="absolute inset-0 w-full h-full">
@@ -145,13 +145,11 @@
class="absolute bottom-0 left-0 z-10 w-full h-full bg-gradient-to-b from-transparent to-gray-900 opacity-30"></div> class="absolute bottom-0 left-0 z-10 w-full h-full bg-gradient-to-b from-transparent to-gray-900 opacity-30"></div>
<img <img
class="absolute inset-0 object-cover object-center w-full h-full transition duration-500 lg:opacity-80 group-hover:opacity-100 group-hover:scale-110" class="absolute inset-0 object-cover object-center w-full h-full transition duration-500 lg:opacity-80 group-hover:opacity-100 group-hover:scale-110"
src="{{ asset('img/pleb_rap.png') }}" alt=""> src="{{ asset('img/einundzwanzig-wallpaper-benrath.png') }}" alt="">
</div> </div>
<div class="relative z-10 flex flex-col items-start justify-start w-full px-6 py-7"> <div class="relative z-10 flex flex-col items-start justify-start w-full px-6 py-7">
<span
class="px-2 py-1 mb-3 text-xs font-semibold tracking-tight text-white uppercase bg-amber-500 rounded-md">{{ __('Plebs together strong') }}</span>
<h4 class="text-4xl font-bold tracking-tight text-gray-100 sm:text-3xl md:text-2xl lg:text-3xl"> <h4 class="text-4xl font-bold tracking-tight text-gray-100 sm:text-3xl md:text-2xl lg:text-3xl">
{{ __('PlebArt') }} {{ __('News') }}
</h4> </h4>
</div> </div>
</a> </a>

View File

@@ -0,0 +1,66 @@
<div class="bg-21gray flex flex-col h-screen justify-between">
<div class="relative bg-21gray px-6 pt-16 pb-20 lg:px-8 lg:pt-24 lg:pb-28">
<div class="absolute inset-0">
<div class="h-1/3 bg-21gray sm:h-2/3"></div>
</div>
<div class="relative mx-auto max-w-7xl">
<div class="text-center">
<h2 class="text-3xl font-bold tracking-tight text-gray-200 sm:text-4xl">{{ __('Dezentral News') }}</h2>
<p class="mx-auto mt-3 max-w-2xl text-xl text-gray-500 sm:mt-4">{{ '' }}</p>
</div>
<div class="mx-auto mt-12 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3">
@foreach($libraryItems as $libraryItem)
<div wire:key="library_item_{{ $libraryItem->id }}"
class="flex flex-col overflow-hidden rounded-lg shadow-[#F7931A] shadow-lg">
<div class="flex-shrink-0">
<a href="{{ route('article.view', ['libraryItem' => $libraryItem]) }}">
<img class="h-48 w-full object-cover"
src="https://images.unsplash.com/photo-1496128858413-b36217c2ce36?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1679&q=80"
alt="{{ $libraryItem->name }}">
</a>
</div>
<div class="flex flex-1 flex-col justify-between bg-white p-6">
<div class="flex-1">
<p class="text-sm font-medium text-indigo-600">
<div
class="">{{ $libraryItem->tags->pluck('name')->join(', ') }}</div>
</p>
<a href="{{ route('article.view', ['libraryItem' => $libraryItem]) }}"
class="mt-2 block">
<p class="text-xl font-semibold text-gray-900">{{ $libraryItem->name }}</p>
<p class="mt-3 text-base text-gray-500">{{ $libraryItem->excerpt }}</p>
</a>
</div>
<div class="mt-6 flex items-center">
<div class="flex-shrink-0">
<div>
<span class="sr-only">{{ $libraryItem->lecturer->name }}</span>
<img class="h-10 w-10 rounded-full"
src="{{ $libraryItem->lecturer->getFirstMediaUrl('avatar') }}"
alt="{{ $libraryItem->lecturer->name }}">
</div>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">
<div class="">{{ $libraryItem->lecturer->name }}</div>
</p>
<div class="flex space-x-1 text-sm text-gray-500">
<time datetime="2020-03-16">{{ $libraryItem->created_at->asDateTime() }}</time>
@if($libraryItem->read_time)
<span aria-hidden="true">&middot;</span>
<span>{{ $libraryItem->read_time }} {{ __('min read') }}</span>
@endif
</div>
</div>
</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
{{-- FOOTER --}}
<livewire:frontend.footer/>
</div>

View File

@@ -0,0 +1,51 @@
<div class="bg-21gray flex flex-col h-screen justify-between">
<div class="overflow-hidden bg-21gray">
<div class="relative mx-auto max-w-7xl py-16 px-6 lg:px-8">
<div class="absolute top-0 bottom-0 left-3/4 hidden w-screen bg-21gray lg:block"></div>
<div class="mx-auto max-w-prose text-base lg:grid lg:max-w-none lg:grid-cols-2 lg:gap-8">
<div>
<h2 class="text-lg font-semibold text-amber-600">{{ $libraryItem->tags->pluck('name')->join(', ') }}</h2>
<h3 class="mt-2 text-3xl font-bold leading-8 tracking-tight text-gray-100 sm:text-4xl">{{ $libraryItem->name }}</h3>
</div>
</div>
<div class="mt-8 lg:grid lg:grid-cols-2 lg:gap-8">
<div class="relative lg:col-start-2 lg:row-start-1">
<svg class="absolute top-0 right-0 -mt-20 -mr-20 hidden lg:block" width="404" height="384" fill="none" viewBox="0 0 404 384" aria-hidden="true">
<defs>
<pattern id="de316486-4a29-4312-bdfc-fbce2132a2c1" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<rect x="0" y="0" width="4" height="4" class="text-gray-200" fill="currentColor" />
</pattern>
</defs>
<rect width="404" height="384" fill="url(#de316486-4a29-4312-bdfc-fbce2132a2c1)" />
</svg>
<div class="relative mx-auto max-w-prose text-base lg:max-w-none">
<figure>
<div class="aspect-w-12 aspect-h-7 lg:aspect-none">
<img class="rounded-lg object-cover object-center shadow-lg" src="{{ $libraryItem->getFirstMediaUrl('main') }}" alt="{{ $libraryItem->name }}" width="1184" height="1376">
</div>
<figcaption class="mt-3 flex text-sm text-gray-200">
<!-- Heroicon name: mini/camera -->
<svg class="h-5 w-5 flex-none text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M1 8a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 018.07 3h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0016.07 6H17a2 2 0 012 2v7a2 2 0 01-2 2H3a2 2 0 01-2-2V8zm13.5 3a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zM10 14a3 3 0 100-6 3 3 0 000 6z" clip-rule="evenodd" />
</svg>
<span class="ml-2">{{ $libraryItem->main_image_caption ?? $libraryItem->name }}</span>
</figcaption>
</figure>
</div>
</div>
<div class="mt-8 lg:mt-0">
<div class="mx-auto max-w-prose text-base lg:max-w-none">
<p class="text-lg text-gray-200">{{ $libraryItem->subtitle }}</p>
</div>
<div class="prose prose-invert mx-auto mt-5 text-gray-100 lg:col-start-1 lg:row-start-1 lg:max-w-none">
<x-markdown>
{!! $libraryItem->value !!}
</x-markdown>
</div>
</div>
</div>
</div>
</div>
{{-- FOOTER --}}
<livewire:frontend.footer/>
</div>

View File

@@ -9,6 +9,14 @@ Route::middleware([
->get('/', \App\Http\Livewire\Frontend\Welcome::class) ->get('/', \App\Http\Livewire\Frontend\Welcome::class)
->name('welcome'); ->name('welcome');
Route::middleware([])
->get('/news', \App\Http\Livewire\News\ArticleOverview::class)
->name('article.overview');
Route::middleware([])
->get('/news/{libraryItem:slug}', \App\Http\Livewire\News\InternArticleView::class)
->name('article.view');
Route::middleware([]) Route::middleware([])
->get('/my-meetups', \App\Http\Livewire\Profile\Meetups::class) ->get('/my-meetups', \App\Http\Livewire\Profile\Meetups::class)
->name('profile.meetups'); ->name('profile.meetups');