front-end article submission form added

This commit is contained in:
HolgerHatGarKeineNode
2023-02-09 22:09:00 +01:00
parent 4d3a3788db
commit 10e5126975
27 changed files with 1599 additions and 17 deletions

Binary file not shown.

View File

@@ -24,6 +24,10 @@ docker run --rm \
```./vendor/bin/sail artisan migrate:fresh --seed``` ```./vendor/bin/sail artisan migrate:fresh --seed```
### Laravel storage link
```./vendor/bin/sail artisan storage:link```
#### Install node dependencies #### Install node dependencies
```vendor/bin/sail yarn install``` ```vendor/bin/sail yarn install```

View File

@@ -0,0 +1,84 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Lecturer;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
class LecturerController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
return Lecturer::query()
->select('id', 'name',)
->orderBy('name')
->when(
$request->search,
fn(Builder $query) => $query
->where('name', 'like', "%{$request->search}%")
)
->when(
$request->exists('selected'),
fn(Builder $query) => $query->whereIn('id', $request->input('selected', [])),
fn(Builder $query) => $query->limit(10)
)
->get()
->map(function (Lecturer $lecturer) {
$lecturer->image = $lecturer->getFirstMediaUrl('avatar', 'thumb');
return $lecturer;
});
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param \App\Models\Lecturer $lecturer
* @return \Illuminate\Http\Response
*/
public function show(Lecturer $lecturer)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Lecturer $lecturer
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Lecturer $lecturer)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Lecturer $lecturer
* @return \Illuminate\Http\Response
*/
public function destroy(Lecturer $lecturer)
{
//
}
}

View File

@@ -19,8 +19,11 @@ class ArticleOverview extends Component
]) ])
->where('type', 'markdown_article') ->where('type', 'markdown_article')
->when(app()->environment('production'), ->when(app()->environment('production'),
fn($query) => $query->whereHas('createdBy.roles', fn($query) => $query
fn($query) => $query->where('roles.name', 'news-editor'))) ->whereHas('createdBy.roles',
fn($query) => $query->where('roles.name', 'news-editor'))
)
->where('approved', true)
->orderByDesc('created_at') ->orderByDesc('created_at')
->get(), ->get(),
])->layout('layouts.app', [ ])->layout('layouts.app', [

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Http\Livewire\News\Form;
use App\Models\LibraryItem;
use Livewire\Component;
use Livewire\WithFileUploads;
class NewsArticleForm extends Component
{
use WithFileUploads;
public ?LibraryItem $libraryItem = null;
public $image;
public $currentImage = 0;
public $images;
public $imagesCloned = [];
public array $temporaryUrls = [];
public function rules()
{
return [
'image' => 'required|mimes:jpeg,png,jpg,gif|max:10240',
'libraryItem.lecturer_id' => 'required',
'libraryItem.name' => 'required',
'libraryItem.type' => 'required',
'libraryItem.language_code' => 'required',
'libraryItem.value' => 'required',
'libraryItem.subtitle' => 'required',
'libraryItem.excerpt' => 'required',
'libraryItem.main_image_caption' => 'required',
'libraryItem.read_time' => 'required',
'libraryItem.approved' => 'boolean',
];
}
public function mount()
{
if ($this->libraryItem === null) {
$this->libraryItem = new LibraryItem([
'type' => 'markdown_article',
'value' => '',
'read_time' => 1,
'language_code' => 'de',
'approved' => auth()
->user()
->hasRole('news-editor'),
]);
}
}
public function updatedImages($value)
{
$clonedImages = collect($this->imagesCloned);
$clonedImages = $clonedImages->push($value);
$this->imagesCloned = $clonedImages->toArray();
$temporaryUrls = collect($this->temporaryUrls);
$temporaryUrls = $temporaryUrls->push($value->temporaryUrl());
$this->temporaryUrls = $temporaryUrls->toArray();
}
public function save()
{
$this->validate();
$this->libraryItem->save();
$this->libraryItem->addMedia($this->image)
->toMediaCollection('main');
return to_route('article.overview', ['country' => null]);
}
public function render()
{
return view('livewire.news.form.news-article-form');
}
}

View File

@@ -0,0 +1,30 @@
<?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->boolean('approved')
->default(true);
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
Schema::table('library_items', function (Blueprint $table) {
//
});
}
};

12
ide.json Normal file
View File

@@ -0,0 +1,12 @@
{
"$schema": "http://laravel-ide.com/schema/laravel-ide-v1.json",
"blade": {
"components": {
"viewPaths": [
{
"path": "resources/views/vendor/wireui/components"
}
]
}
}
}

View File

@@ -0,0 +1,47 @@
/*!
* FilePondPluginImageEdit 1.6.3
* Licensed under MIT, https://opensource.org/licenses/MIT/
* Please visit https://pqina.nl/filepond/ for details.
*/
/* eslint-disable */
.filepond--action-edit-item.filepond--action-edit-item {
width: 2em;
height: 2em;
padding: 0.1875em;
}
.filepond--action-edit-item.filepond--action-edit-item[data-align*='center'] {
margin-left: -0.1875em;
}
.filepond--action-edit-item.filepond--action-edit-item[data-align*='bottom'] {
margin-bottom: -0.1875em;
}
.filepond--action-edit-item-alt {
border: none;
line-height: inherit;
background: transparent;
font-family: inherit;
color: inherit;
outline: none;
padding: 0;
margin: 0 0 0 0.25em;
pointer-events: all;
position: absolute;
}
.filepond--action-edit-item-alt svg {
width: 1.3125em;
height: 1.3125em;
}
.filepond--action-edit-item-alt span {
font-size: 0;
opacity: 0;
}
.filepond--root[data-style-panel-layout~='circle'] .filepond--action-edit-item {
opacity: 1 !important;
visibility: visible !important;
}

1047
public/dist/filepond.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,8 @@
import './bootstrap' import './bootstrap'
// Import the plugin styles
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
import Alpine from 'alpinejs' import Alpine from 'alpinejs'
import collapse from '@alpinejs/collapse' import collapse from '@alpinejs/collapse'
import intersect from '@alpinejs/intersect' import intersect from '@alpinejs/intersect'

View File

@@ -583,7 +583,7 @@
"Changes": "", "Changes": "",
"Exception": "", "Exception": "",
"Action Happened At": "", "Action Happened At": "",
"Action": "", "Action": "Aktion",
"CSV (.csv)": "", "CSV (.csv)": "",
"Excel (.xlsx)": "", "Excel (.xlsx)": "",
"Filename": "", "Filename": "",
@@ -634,8 +634,8 @@
"Here you can see all events of :name.": "Hier siehst du alle Kurs-Termine von :name.", "Here you can see all events of :name.": "Hier siehst du alle Kurs-Termine von :name.",
"This is the introduction text that is shown on the landing page.": "Das ist der Einführungstext, der auf der Landing-Page angezeigt wird.", "This is the introduction text that is shown on the landing page.": "Das ist der Einführungstext, der auf der Landing-Page angezeigt wird.",
"This is the subtitle on the landing page.": "Das ist der Untertitel auf der Landing-Page des Dozenten.", "This is the subtitle on the landing page.": "Das ist der Untertitel auf der Landing-Page des Dozenten.",
"Subtitle": "Untertitel auf der Landing-Page", "Subtitle": "Untertitel",
"Intro": "Intro auf der Landing-Page", "Intro": "Intro",
"This lecturer has not yet written an introduction.": "Dieser Dozent hat noch keine Einführung geschrieben.", "This lecturer has not yet written an introduction.": "Dieser Dozent hat noch keine Einführung geschrieben.",
"If your city is not listed, please create it first.": "Wenn deine Stadt nicht aufgeführt ist, erstelle sie bitte zuerst.", "If your city is not listed, please create it first.": "Wenn deine Stadt nicht aufgeführt ist, erstelle sie bitte zuerst.",
"You get a point when you log in.": "Du bekommst einen Punkt, wenn du dich einloggst.", "You get a point when you log in.": "Du bekommst einen Punkt, wenn du dich einloggst.",
@@ -731,5 +731,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "Auf dieser Karte kannst du sehen, wo sich georangepillte Bücher befinden. Du kannst auch auf einen Marker klicken, um zum Suchergebnis zu gelangen.", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "Auf dieser Karte kannst du sehen, wo sich georangepillte Bücher befinden. Du kannst auch auf einen Marker klicken, um zum Suchergebnis zu gelangen.",
"Community": "Community", "Community": "Community",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "Dies ist die Community, der das Meetup angehört. Wenn eine Community nicht aufgeführt ist, kontaktiere bitte den Administrator.", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "Dies ist die Community, der das Meetup angehört. Wenn eine Community nicht aufgeführt ist, kontaktiere bitte den Administrator.",
"World Map": "Weltkarte" "World Map": "Weltkarte",
"Submit news articles": "Artikel einreichen",
"News Article": "News-Artikel",
"Author": "Autor",
"Ex: Photo by Timothy Vollmer\/ CC BY": "Zum Beispiel: Foto von Timothy Vollmer\/ CC BY",
"Article as Markdown": "Artikel als Markdown",
"For images in Markdown, please use eg. Imgur or another provider.": "Für Bilder in Markdown, benutze bitte z.B. Imgur oder einen anderen Anbieter."
} }

View File

@@ -726,5 +726,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -726,5 +726,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -727,5 +727,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -727,5 +727,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -727,5 +727,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -727,5 +727,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -727,5 +727,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -727,5 +727,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -701,5 +701,11 @@
"On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "", "On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.": "",
"Community": "", "Community": "",
"This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "", "This is the community that the meetup belongs to. If a community is not listed, please contact the administrator.": "",
"World Map": "" "World Map": "",
"Submit news articles": "",
"News Article": "",
"Author": "",
"Ex: Photo by Timothy Vollmer\/ CC BY": "",
"Article as Markdown": "",
"For images in Markdown, please use eg. Imgur or another provider.": ""
} }

View File

@@ -0,0 +1,30 @@
<div
wire:ignore
x-data
x-init="
FilePond.registerPlugin(
FilePondPluginImagePreview,
FilePondPluginImageExifOrientation,
FilePondPluginFileValidateSize,
FilePondPluginImageEdit
);
FilePond.setOptions({
labelIdle: '{{ 'Drag & Drop Deiner Dateien oder <span class="filepond--label-action"> in Ordner suchen </span>' }}',
allowMultiple: {{ isset($attributes['multiple']) ? 'true' : 'false' }},
server: {
process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
@this.upload('{{ $attributes['wire:model'] }}', file, load, error, progress)
},
revert: (filename, load) => {
@this.removeUpload('{{ $attributes['wire:model'] }}', filename, load)
},
load: (source, load, error, progress, abort, headers) => {
@this.load('{{ $attributes['wire:model'] }}', load, error, progress, abort, headers)
},
},
});
FilePond.create($refs.input);
"
>
<input type="file" x-ref="input" name="{{ $attributes['name'] }}">
</div>

View File

@@ -0,0 +1,60 @@
<div
wire:ignore
x-data="{
value: @entangle($attributes->wire('model')).defer,
init() {
let editor = new EasyMDE({
element: this.$refs.editor,
lineNumbers: true,
uploadImage: false,
{{-- imageMaxSize: 1024 * 1024 * 10,--}}
{{-- imageUploadFunction: (file, onSuccess, onError) => {--}}
{{-- @this.upload('images', file, (uploadedFilename) => {--}}
{{-- const currentImage = @this.get('currentImage');--}}
{{-- const temporaryUrls = @this.get('temporaryUrls');--}}
{{-- onSuccess(temporaryUrls[currentImage]);--}}
{{-- @this.set('currentImage', currentImage + 1)--}}
{{-- }, () => {--}}
{{-- // Error callback.--}}
{{-- }, (event) => {--}}
{{-- // Progress callback.--}}
{{-- // event.detail.progress contains a number between 1 and 100 as the upload progresses.--}}
{{-- })--}}
{{-- },--}}
showIcons: [
'heading',
'heading-smaller',
'heading-bigger',
'heading-1',
'heading-2',
'heading-3',
'code',
'table',
'quote',
'strikethrough',
'unordered-list',
'ordered-list',
'clean-block',
'horizontal-rule',
'undo',
'redo',
//'upload-image',
],
})
editor.value(this.value)
editor.codemirror.on('change', () => {
this.value = editor.value()
})
},
}"
class="w-full"
>
<textarea x-ref="editor"></textarea>
<style>
.EasyMDEContainer {
background-color: white;
}
</style>
</div>

View File

@@ -13,8 +13,6 @@
<!-- Fonts --> <!-- Fonts -->
@googlefonts @googlefonts
<!-- Scripts --> <!-- Scripts -->
<link rel="stylesheet" href="{{ asset('vendor/jvector/jquery-jvectormap-2.0.5.css') }}" type="text/css"
media="screen"/>
<script src="{{ asset('dist/jquery.js') }}"></script> <script src="{{ asset('dist/jquery.js') }}"></script>
<script src="{{ asset('vendor/jvector/jquery-jvectormap-2.0.5.min.js') }}"></script> <script src="{{ asset('vendor/jvector/jquery-jvectormap-2.0.5.min.js') }}"></script>
<script src="{{ asset('vendor/jvector/maps/world-mill.js') }}"></script> <script src="{{ asset('vendor/jvector/maps/world-mill.js') }}"></script>
@@ -38,6 +36,9 @@
<x-comments::scripts/> <x-comments::scripts/>
@vite(['resources/css/app.css', 'resources/js/app.js']) @vite(['resources/css/app.css', 'resources/js/app.js'])
<!-- Styles --> <!-- Styles -->
<link rel="stylesheet" href="{{ asset('vendor/jvector/jquery-jvectormap-2.0.5.css') }}" type="text/css"
media="screen"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.css">
<x-comments::styles/> <x-comments::styles/>
<x-embed-styles /> <x-embed-styles />
@livewireStyles @livewireStyles
@@ -111,5 +112,6 @@
@livewireScripts @livewireScripts
<!-- ProductLift SDK - Include it only once --> <!-- ProductLift SDK - Include it only once -->
<script defer src="https://bitcoin.productlift.dev/widgets_sdk"></script> <script defer src="https://bitcoin.productlift.dev/widgets_sdk"></script>
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
</body> </body>
</html> </html>

View File

@@ -9,6 +9,14 @@
<div> <div>
<img class="h-32 object-cover" src="{{ asset('img/einundzwanzig-news-colored.png') }}" alt=""> <img class="h-32 object-cover" src="{{ asset('img/einundzwanzig-news-colored.png') }}" alt="">
</div> </div>
<div>
<x-button
:href="route('news.form')"
primary>
<i class="fa fa-thin fa-plus"></i>
{{ __('Submit news articles') }}
</x-button>
</div>
</div> </div>
<div class="mx-auto mt-2 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3"> <div class="mx-auto mt-2 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3">

View File

@@ -0,0 +1,101 @@
<div class="container p-4 mx-auto bg-21gray my-2">
<div class="pb-5 flex flex-row justify-between">
<h3 class="text-lg font-medium leading-6 text-gray-200">{{ __('News Article') }}</h3>
<div class="flex flex-row space-x-2 items-center">
<div>
<x-button :href="route('article.overview', ['country' => null])">
<i class="fa fa-thin fa-arrow-left"></i>
{{ __('Back') }}
</x-button>
</div>
</div>
</div>
<form class="space-y-8 divide-y divide-gray-700 pb-24">
<div class="space-y-8 divide-y divide-gray-700 sm:space-y-5">
<div class="mt-6 sm:mt-5 space-y-6 sm:space-y-5">
<x-input.group :for="md5('libraryItem.lecturer_id')" :label="__('Author')">
<x-select
:clearable="false"
wire:model="libraryItem.lecturer_id"
:searchable="true"
:async-data="[
'api' => route('api.lecturers.index'),
'method' => 'GET', // default is GET
]"
:template="[
'name' => 'user-option',
'config' => ['src' => 'image']
]"
option-label="name"
option-value="id"
/>
</x-input.group>
<x-input.group :for="md5('image')" :label="__('Main picture')">
<div class="py-4">
@if ($image)
<div class="text-gray-200">{{ __('Preview') }}:</div>
<img class="h-48 object-contain" src="{{ $image->temporaryUrl() }}">
@endif
</div>
<input class="text-gray-200" type="file" wire:model="image">
@error('image') <span class="text-red-500">{{ $message }}</span> @enderror
</x-input.group>
<x-input.group :for="md5('libraryItem.main_image_caption')" :label="__('Main image caption')">
<x-input autocomplete="off" wire:model.debounce="libraryItem.main_image_caption"
:placeholder="__('Main image caption')"
:cornerHint="__('Ex: Photo by Timothy Vollmer/ CC BY')"/>
</x-input.group>
<x-input.group :for="md5('libraryItem.name')" :label="__('Title')">
<x-input autocomplete="off" wire:model.debounce="libraryItem.name"
:placeholder="__('Title')"/>
</x-input.group>
<x-input.group :for="md5('libraryItem.subtitle')" :label="__('Subtitle')">
<x-input autocomplete="off" wire:model.debounce="libraryItem.subtitle"
:placeholder="__('Subtitle')"/>
</x-input.group>
<x-input.group :for="md5('libraryItem.excerpt')" :label="__('Excerpt')">
<x-textarea autocomplete="off" wire:model.debounce="libraryItem.excerpt"
:placeholder="__('Excerpt')"/>
</x-input.group>
<x-input.group :for="md5('libraryItem.language_code')" :label="__('Language Code')">
<x-select
:clearable="false"
wire:model="libraryItem.language_code"
:options="collect(config('languages.languages'))->map(fn($value, $key) => ['id' => $key, 'name' => $value])->toArray()"
option-label="name"
option-value="id"
/>
</x-input.group>
<x-input.group :for="md5('libraryItem.value')" :label="__('Article as Markdown')">
<span
class="text-amber-500 text-xs py-2">{{ __('For images in Markdown, please use eg. Imgur or another provider.') }}</span>
<x-input.simple-mde wire:model.defer="libraryItem.value"/>
@error('libraryItem.value') <span class="text-red-500 py-2">{{ $message }}</span> @enderror
</x-input.group>
<x-input.group :for="md5('libraryItem.read_time')" :label="__('Time to read')">
<x-inputs.number min="1" autocomplete="off" wire:model.debounce="libraryItem.read_time"
:placeholder="__('Time to read')" :hint="__('How many minutes to read?')"/>
</x-input.group>
<x-input.group :for="md5('meetupEvent.link')" label="">
<x-button primary wire:click="save">
<i class="fa fa-thin fa-save"></i>
{{ __('Save') }}
</x-button>
</x-input.group>
</div>
</div>
</form>
</div>

View File

@@ -28,6 +28,7 @@ Route::middleware([])
->group(function () { ->group(function () {
Route::resource('countries', \App\Http\Controllers\Api\CountryController::class); Route::resource('countries', \App\Http\Controllers\Api\CountryController::class);
Route::resource('meetup', \App\Http\Controllers\Api\MeetupController::class); Route::resource('meetup', \App\Http\Controllers\Api\MeetupController::class);
Route::resource('lecturers', \App\Http\Controllers\Api\LecturerController::class);
Route::resource('languages', \App\Http\Controllers\Api\LanguageController::class); Route::resource('languages', \App\Http\Controllers\Api\LanguageController::class);
Route::get('meetups', function () { Route::get('meetups', function () {
return \App\Models\Meetup::query() return \App\Models\Meetup::query()

View File

@@ -23,6 +23,17 @@ Route::middleware([])
->get('/news', \App\Http\Livewire\News\ArticleOverview::class) ->get('/news', \App\Http\Livewire\News\ArticleOverview::class)
->name('article.overview'); ->name('article.overview');
/*
* News
* */
Route::middleware([])
->as('news.')
->prefix('/news')
->group(function () {
Route::get('/form/{libraryItem?}', \App\Http\Livewire\News\Form\NewsArticleForm::class)
->name('form');
});
Route::middleware([]) Route::middleware([])
->get('/news/{libraryItem:slug}', \App\Http\Livewire\News\InternArticleView::class) ->get('/news/{libraryItem:slug}', \App\Http\Livewire\News\InternArticleView::class)
->name('article.view'); ->name('article.view');