Skip to content

Commit

Permalink
Merge pull request #636 from SlovakNationalGallery/WEBUMENIA-1740-art…
Browse files Browse the repository at this point in the history
…work-highlight-backend

Artwork highlight back-end (+ Tailwind admin components)
  • Loading branch information
eronisko authored Feb 24, 2022
2 parents 044c4f0 + 75d94b0 commit 843690f
Show file tree
Hide file tree
Showing 26 changed files with 681 additions and 25 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file[^1].

## [Unreleased]
### Added
- Featured Artworks back-end section
- new Tailwind component for back-end/admin

### Changed
- font loading (fix for Source Serif Pro)

Expand Down
77 changes: 77 additions & 0 deletions app/FeaturedArtwork.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;

class FeaturedArtwork extends Model
{
protected $fillable = [
'is_published',
'item',
'item_id',
'title',
'description',
];

public function item()
{
return $this->belongsTo(Item::class);
}

public function getIsPublishedAttribute() {
return !!$this->published_at;
}

public function setIsPublishedAttribute(bool $isPublished) {
if ($this->is_published === $isPublished) return;
if (!$isPublished) return $this->attributes['published_at'] = null;

$this->attributes['published_at'] = Carbon::now();
}

public function scopePublished($query)
{
return $query->where('published_at', '<=', Carbon::now());
}

public function getAuthorLinksAttribute()
{
if (!$this->item) return;

return $this->item
->authors_with_authorities
->map(fn ($a) => (object) [
'label' => formatName($a->name),
'url' => isset($a->authority) ? $a->authority->getUrl() : route('frontend.catalog.index', ['author' => $a->name])
]);
}

public function getMetadataLinksAttribute()
{
if (!$this->item) return;

$dating = (object) [
'label' => $this->item->getDatingFormated(),
'url' => null,
];

$techniques = collect($this->item->techniques)
->map(fn ($t) => (object) [
'label' => $t,
'url' => route('frontend.catalog.index', ['technique' => $t]),
]);

$media = collect($this->item->mediums)
->map(fn ($m) => (object) [
'label' => $m,
'url' => route('frontend.catalog.index', ['medium' => $m]),
]);


return collect([$dating])
->concat($techniques)
->concat($media);
}
}
91 changes: 91 additions & 0 deletions app/Http/Controllers/Admin/FeaturedArtworkController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace App\Http\Controllers\Admin;

use App\FeaturedArtwork;
use App\Http\Controllers\Controller;
use App\Item;
use Illuminate\Http\Request;

class FeaturedArtworkController extends Controller
{
private static $rules = [
'title' => 'required',
'description' => 'required',
'item_id' => 'required'
];

public function index()
{
return view('featured_artworks.index', [
'artworks' => FeaturedArtwork::query()
->with('item')
->orderBy('id', 'desc')
->get(),
'lastPublishedId' => FeaturedArtwork::query()
->published()
->orderBy('published_at', 'desc')
->value('id')
]);
}

public function create(Request $request)
{
$item = $request->query('itemId') ? Item::find($request->query('itemId')) : null;

return view('featured_artworks.form', [
'artwork' => new FeaturedArtwork([
'title' => optional($item)->title,
'description' => optional($item)->description,
'item' => $item,
])
]);
}

public function edit(FeaturedArtwork $featuredArtwork)
{
return view('featured_artworks.form', [
'artwork' => $featuredArtwork,
]);
}

public function store(Request $request)
{
$request->validate(self::$rules);
$featuredArtwork = FeaturedArtwork::create(array_merge(
$request->input(),
[
'is_published' => $request->boolean('is_published')
]
));

return redirect()
->route('featured-artworks.index')
->with('message', "Vybrané dielo \"{$featuredArtwork->title}\" bolo vytvorené");
}

public function update(Request $request, FeaturedArtwork $featuredArtwork)
{
$request->validate(self::$rules);

$featuredArtwork->update(array_merge(
$request->input(),
[
'is_published' => $request->boolean('is_published')
]
));

return redirect()
->route('featured-artworks.index')
->with('message', "Vybrané dielo \"{$featuredArtwork->title}\" bolo upravené");
}

public function destroy(FeaturedArtwork $featuredArtwork)
{
$featuredArtwork->delete();

return redirect()
->route('featured-artworks.index')
->with('message', 'Odporúčané dielo bolo zmazané');
}
}
18 changes: 18 additions & 0 deletions app/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,24 @@ public function getAuthorsWithoutAuthority()
->keys();
}

public function getAuthorsWithAuthoritiesAttribute()
{
$authorities = $this
->authorities
->map(fn ($authority) => (object) [
'name' => $authority->name,
'authority' => $authority
]);

$authors = $this
->getAuthorsWithoutAuthority()
->map(fn ($author) => (object) [
'name' => $author
]);

return $authorities->concat($authors);
}

public function getFirstAuthorAttribute($value)
{
$authors_array = $this->makeArray($this->author);
Expand Down
59 changes: 59 additions & 0 deletions app/View/Components/Admin/Form.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace App\View\Components\Admin;

use Illuminate\Database\Eloquent\Model;
use Illuminate\View\Component;
use Illuminate\Support\Str;

class Form extends Component
{
public Model $model;

public string $url;

public string $method;

/**
* Create a new component instance.
*
* @return void
*/
public function __construct(Model $model, ?string $url = null, ?string $method = null)
{
$this->model = $model;
$this->url = $this->buildUrl($url);
$this->method = $this->buildMethod($method);
}

private function buildUrl(?string $url): string {
if ($url) return $url;

// Try to guess url from model class
$routeName = Str::of(class_basename($this->model))->plural()->kebab();

if ($this->model->exists) {
return route("$routeName.update", [$this->model]);
}

return route("$routeName.store");
}

private function buildMethod(?string $method): string {
if ($method) return $method;

if ($this->model->exists) return 'patch';

return 'post';
}

/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render()
{
return view('components.admin.form');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateFeaturedArtworksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('featured_artworks', function (Blueprint $table) {
$table->id();
$table->string('item_id');
$table->foreign('item_id')->references('id')->on('items');
$table->string('title');
$table->text('description');
$table->dateTime('published_at')->nullable();
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('featured_artworks');
}
}
21 changes: 13 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"dependencies": {
"bootstrap": "^3.4.1",
"clipboard": "^2.0.6",
"corejs-typeahead": "^1.3.1",
"date-fns": "^2.25.0",
"debounce": "1.2.0",
"flickity": "^2.2.1",
Expand Down
4 changes: 3 additions & 1 deletion resources/js/admin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
window.debounce = require('debounce');
window.Vue = require('vue').default;

Vue.component('linked-combos', require('./components/vue/linked-combos').default);
Vue.component('admin-links-input', require('./components/admin/LinksInput.vue').default);
Vue.component('autocomplete', require('./components/Autocomplete.vue').default);
Vue.component('linked-combos', require('./components/vue/linked-combos').default);
Vue.component('query-string', require('./components/QueryString.vue').default);

new Vue({ el: '#wrapper' })
Loading

0 comments on commit 843690f

Please sign in to comment.