Initial commit
This commit is contained in:
13
resources/views/components/breadcrumbs.blade.php
Normal file
13
resources/views/components/breadcrumbs.blade.php
Normal file
@@ -0,0 +1,13 @@
|
||||
@unless ($breadcrumbs->isEmpty())
|
||||
<div class="breadcrumb">
|
||||
@foreach ($breadcrumbs as $breadcrumb)
|
||||
|
||||
@if ($breadcrumb->url && !$loop->last)
|
||||
<a href="{{ $breadcrumb->url }}">{{ $breadcrumb->title }}</a> <span>›</span>
|
||||
@else
|
||||
<span>{{ $breadcrumb->title }}</span>
|
||||
@endif
|
||||
|
||||
@endforeach
|
||||
</div>
|
||||
@endunless
|
||||
8
resources/views/components/entry-meta-item.blade.php
Normal file
8
resources/views/components/entry-meta-item.blade.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<div class="entry-meta-item">
|
||||
<span class="entry-meta-label">{{ $label }}</span>
|
||||
@if( $route !== "none" )
|
||||
<a href="{{ $route }}" class="entry-meta-value">{{ $value }}</a>
|
||||
@else
|
||||
<span class="entry-meta-value">{{ $value }}</span>
|
||||
@endif
|
||||
</div>
|
||||
3
resources/views/components/entry-section-title.blade.php
Normal file
3
resources/views/components/entry-section-title.blade.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<h2 class="entry-section-title">
|
||||
@if( $icon != '' )<i data-lucide="{{ $icon }}"></i>@endif {{ $label }}
|
||||
</h2>
|
||||
3
resources/views/components/error-block.blade.php
Normal file
3
resources/views/components/error-block.blade.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<div class="block-error">
|
||||
<i data-lucide="{{ $errorArray['icon'] ?? '' }}"></i> {{ sprintf( $errorArray['message'], $message ) }}
|
||||
</div>
|
||||
6
resources/views/components/form-error-text.blade.php
Normal file
6
resources/views/components/form-error-text.blade.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<span class="form-error-text">
|
||||
@if( $icon )
|
||||
<i data-lucide="alert-triangle" size="14"></i>
|
||||
@endif
|
||||
{{ $message }}
|
||||
</span>
|
||||
10
resources/views/components/form-field-title.blade.php
Normal file
10
resources/views/components/form-field-title.blade.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<label class="form-label">
|
||||
{{ $name }}
|
||||
@if( $required )
|
||||
<span style="color:red">*</span>
|
||||
@endif
|
||||
@if( $helper !== "" )
|
||||
<span>{{ $helper }}</span>
|
||||
@endif
|
||||
</label>
|
||||
{{ $slot }}
|
||||
7
resources/views/components/form-group-title.blade.php
Normal file
7
resources/views/components/form-group-title.blade.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<h3 class="form-group-title">
|
||||
@if( $icon !== "" )
|
||||
<i data-lucide="{{ $icon }}" color="var(--rhpz-orange"></i>
|
||||
@endif
|
||||
{{ $label }}
|
||||
</h3>
|
||||
{{ $slot }}
|
||||
34
resources/views/components/gallery-field.blade.php
Normal file
34
resources/views/components/gallery-field.blade.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<div x-data="GalleryManager()" x-init="init(@js($oldPaths))">
|
||||
<x-form-field-title name="Screenshots" helper="At least 1 Screenshot required, Maximum 20." required="{{ $required ? 'true' : 'false' }}" />
|
||||
<div class="form-group main-image-grid">
|
||||
<div class="form-upload" style="flex:1;" :class="{ 'disabled': isFull }">
|
||||
<input type="file" id="gallery-field" accept="image/png, image/jpeg, image/webp" multiple :disabled="isFull" @change="handleSubmitFiles($event)">
|
||||
<div class="form-upload-placeholder level">
|
||||
<i data-lucide="file-archive" size="36" style="margin-bottom:15px;color:var(--text2)"></i>
|
||||
<div style="font-size: 1.1rem;color:var(--text);margin-bottom:5px;">
|
||||
Click or drag'n drop files here.
|
||||
</div>
|
||||
<div style="font-size:0.85rem;color:var(--text2);">
|
||||
Accepted: PNG, JPG or WebP
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-gallery form-group level" style="flex:4;">
|
||||
<template x-for="(image,i) in images" :key="image.serverFilePath">
|
||||
<div class="gallery-item">
|
||||
<div class="form-image-preview-wrap">
|
||||
<img :src="image.preview" :alt="image.name">
|
||||
<button type="button" class="form-image-remove" @click="handleRemoveFile(i)">
|
||||
X
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template x-for="(image, i) in images" :key="image.serverFilePath">
|
||||
<input type="hidden" name="gallery[]" :value="image.serverFilePath">
|
||||
</template>
|
||||
|
||||
</div>
|
||||
29
resources/views/components/languages-selector.blade.php
Normal file
29
resources/views/components/languages-selector.blade.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php /** @var \App\Models\Language $language */ ?>
|
||||
<div class="languages-selector form-group level" x-data="{
|
||||
search: '',
|
||||
selected: {{ JS::from( (array) $selected ) }},
|
||||
toggle(value){
|
||||
const i = this.selected.indexOf(value);
|
||||
i === -1 ? this.selected.push(value) : this.selected.splice(i,1);
|
||||
},
|
||||
valueSelect(value){
|
||||
return this.selected.includes(value);
|
||||
},
|
||||
get count(){ return this.selected.length; }
|
||||
}">
|
||||
<div class="language-search">
|
||||
<i data-lucide="search"></i>
|
||||
<input type="text" x-model="search" placeholder="Search language" autocomplete="off">
|
||||
<button class="btn" type="button" x-show="search !== ''" @click="search = ''" x-cloak>
|
||||
<i data-lucide="x"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="language-list" id="languages-group">
|
||||
@foreach( $languages as $language )
|
||||
<label class="language-item" x-show="'{{ strtolower($language->name) }}'.includes(search.toLowerCase())">
|
||||
<input type="checkbox" name="languages[]" value="{{ $language->id }}" x-model="selected" :value="{{ $language->id }}" {{ in_array($language->id, $selected) ? 'checked' : '' }}> {{ $language->name }}
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
</div>
|
||||
37
resources/views/components/main-image-field.blade.php
Normal file
37
resources/views/components/main-image-field.blade.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<div x-data="MainImageManager()" x-init="init('{{$oldPath}}')">
|
||||
<x-form-field-title name="Main image" helper="This will show up on the index and on top of the entry. A screenshot or custom cover is prefered else all entries of same game will look the same." required="{{ $required ? 'true' : 'false' }}" />
|
||||
<div class="form-group main-image-grid">
|
||||
<div class="form-upload" style="flex:4;">
|
||||
<input type="file" id="main-image-field" accept="image/png, image/jpeg, image/webp" @change="handleSubmitFile($event)">
|
||||
<div class="form-upload-placeholder level">
|
||||
<i data-lucide="file-archive" size="36" style="margin-bottom:15px;color:var(--text2)"></i>
|
||||
<div style="font-size: 1.1rem;color:var(--text);margin-bottom:5px;">
|
||||
Click or drag'n drop files here.
|
||||
</div>
|
||||
<div style="font-size:0.85rem;color:var(--text2);">
|
||||
Accepted: PNG, JPG or WebP
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="main-image" x-model="serverFilePath">
|
||||
</div>
|
||||
<div class="form-image" style="flex:1">
|
||||
<div class="form-image-placeholder" x-show="!preview">
|
||||
<i data-lucide="image" size="48"></i>
|
||||
</div>
|
||||
<div class="form-image-preview" x-show="preview" x-cloak>
|
||||
<div class="form-image-preview-wrap">
|
||||
<img :src="preview" alt="Main Image">
|
||||
|
||||
<button type="button" class="form-image-remove" @click="handleRemoveFile()">
|
||||
<i data-lucide="x"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="form-image-info">
|
||||
<span x-text="name"></span>
|
||||
</div>
|
||||
<span class="form-error-text" x-show="error !== null" x-text="error"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
16
resources/views/components/markdown-textarea.blade.php
Normal file
16
resources/views/components/markdown-textarea.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<div x-data
|
||||
x-init="
|
||||
window.mde_{{ $name }} = new EasyMDE({
|
||||
element: $el.querySelector('#field_{{ $name }}'),
|
||||
minHeight: '{{ $minHeight }}',
|
||||
toolbar: {{ Js::from( $toolbar ) }},
|
||||
autosave: {
|
||||
enabled: true,
|
||||
uniqueId: '{{ $name }}',
|
||||
delay: 1000,
|
||||
},
|
||||
})
|
||||
"
|
||||
>
|
||||
<textarea class="form-textarea" id="field_{{ $name }}" name="{{ $name }}">{{ $value }}</textarea>
|
||||
</div>
|
||||
40
resources/views/components/menu.blade.php
Normal file
40
resources/views/components/menu.blade.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<nav id="menu">
|
||||
|
||||
<div class="menu-header">
|
||||
<div class="menu-logo">
|
||||
RP
|
||||
</div>
|
||||
<div class="menu-title">
|
||||
Romhack Plaza
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu-navigation">
|
||||
|
||||
|
||||
<div class="menu-group">
|
||||
<div class="menu-group-title">Website</div>
|
||||
<a href="{{ route('home') }}"
|
||||
@class(['menu-item', 'active' => request()->routeIs('home')]) >
|
||||
<i data-lucide="home"></i><span>Home</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="menu-user">
|
||||
<div class="menu-user-avatar">
|
||||
<x-xen-foro-avatar />
|
||||
</div>
|
||||
<div class="menu-user-info">
|
||||
<span class="username">
|
||||
{{ \Auth::user()?->username ?? "Guest" }}
|
||||
</span>
|
||||
<span class="user_role">
|
||||
Lorem
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
31
resources/views/components/staff-credits-field.blade.php
Normal file
31
resources/views/components/staff-credits-field.blade.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<div x-data='Credits()' x-init="init(@js($oldStaffCredits))">
|
||||
<x-form-field-title name="Staff/Credits" />
|
||||
<template x-if="credits.length > 0">
|
||||
<div class="form-group grid-credits">
|
||||
<div><x-form-field-title name="Name" /></div>
|
||||
<div><x-form-field-title name="Description" /></div>
|
||||
<div><x-form-field-title name="Actions" /></div>
|
||||
<template x-for="(credit,i) in credits" :key="i">
|
||||
<div style="display:contents">
|
||||
<div>
|
||||
<input class="form-input" type="text" x-model="credit.name" autocomplete="off">
|
||||
</div>
|
||||
<div>
|
||||
<input class="form-input" type="text" x-model="credit.description" autocomplete="off">
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="btn" @click="removeCredits(i)">
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<input type="hidden" name="staff_credits" x-model="JSON.stringify(credits)">
|
||||
<div style="display:flex;justify-content:flex-end;margin-top:10px;">
|
||||
<button type="button" class="btn primary" @click="addEmptyCredits()">
|
||||
Add a credit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
28
resources/views/components/submit-entry-status.blade.php
Normal file
28
resources/views/components/submit-entry-status.blade.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="submit-level" x-data="{
|
||||
nsfw: null,
|
||||
state: '{{ old('submit-state', $defaultState) }}',
|
||||
init(){
|
||||
this.$watch('nsfw', (val) => {
|
||||
if( val && this.state === 'published' ) {
|
||||
this.state = 'draft';
|
||||
}
|
||||
});
|
||||
}
|
||||
}" x-init="init()">
|
||||
<div>
|
||||
@if( section_must_be( [ 'romhacks', 'homebrew' ], $section ) )
|
||||
<label class="nsfw-label"><input id="nsfw-checkbox" type="checkbox" name="nsfw-entry" x-model="nsfw" style="transform: scale(1.5)"> NSFW</label>
|
||||
@endif
|
||||
</div>
|
||||
<select class="form-select" name="submit-state" x-model="state">
|
||||
@foreach( $states as $k => $v )
|
||||
@if( $k == 'published' )
|
||||
<template x-if="!nsfw">
|
||||
<option value="{{ $k }}" {{ $defaultState == $k ? 'selected' : '' }}>{{ $v }}</option>
|
||||
</template>
|
||||
@else
|
||||
<option value="{{ $k }}" {{ $defaultState == $k ? 'selected' : '' }}>{{ $v }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
3
resources/views/components/success-block.blade.php
Normal file
3
resources/views/components/success-block.blade.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<div class="block-success">
|
||||
<i data-lucide="{{ $successArray['icon'] ?? '' }}"></i> {{ sprintf( $successArray['message'], $message ) }}
|
||||
</div>
|
||||
16
resources/views/components/topbar.blade.php
Normal file
16
resources/views/components/topbar.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<header id="topbar">
|
||||
<button class="mobile-toggle">
|
||||
<i data-lucide="menu"></i>
|
||||
</button>
|
||||
|
||||
<div class="search-bar">
|
||||
<i data-lucide="search" size="18" color="var(--text2)"></i>
|
||||
<input type="text">Search</input>
|
||||
</div>
|
||||
|
||||
<div class="topbar-actions">
|
||||
<button class="btn">
|
||||
<i data-lucide="bell" size="18"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
16
resources/views/components/xen-foro-avatar.blade.php
Normal file
16
resources/views/components/xen-foro-avatar.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
@if(!$user)
|
||||
<i data-lucide="user"></i>
|
||||
@else
|
||||
@if($user->getAvatarUrl())
|
||||
<img src="{{ $user->getAvatarUrl('m') }}" alt="avatar">
|
||||
@else
|
||||
<div style="
|
||||
background: {{\App\Helpers\XenForoHelpers::getAvatarColor($user) }};
|
||||
width: 40px; height: 40px; border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
color:var(--text); font-weight: bold;
|
||||
">
|
||||
{{ \App\Helpers\XenForoHelpers::getAvatarLetter($user) }}
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
11
resources/views/entries/index.blade.php
Normal file
11
resources/views/entries/index.blade.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>RomHack Plaza</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Bienvenue sur RomHack Plaza</h1>
|
||||
<p>Le catalogue est en construction.</p>
|
||||
</body>
|
||||
</html>
|
||||
97
resources/views/entries/show.blade.php
Normal file
97
resources/views/entries/show.blade.php
Normal file
@@ -0,0 +1,97 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('page-title', $entry->title . " - " . config('app.name') )
|
||||
|
||||
@section('content')
|
||||
{{ \Diglactic\Breadcrumbs\Breadcrumbs::render() }}
|
||||
<article id="entry-container">
|
||||
<div class="entry-header">
|
||||
<div class="entry-cover">
|
||||
@if( $entry->main_image )
|
||||
<img src="{{ Storage::url($entry->main_image) }}">
|
||||
@else
|
||||
<div class="entry-cover-placeholder">
|
||||
<i data-lucide="image" size="48"></i>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="entry-info">
|
||||
<h1 class="entry-title">
|
||||
{{ $entry->title }}
|
||||
</h1>
|
||||
<div class="entry-authors">
|
||||
@forelse( $entry->authors as $author)
|
||||
@if($loop->first)By @endif
|
||||
{{ $author->name }}
|
||||
@if( !$loop->last ), @endif
|
||||
@empty
|
||||
No authors
|
||||
@endforelse
|
||||
</div>
|
||||
<div class="entry-meta-grid">
|
||||
@if( $entry->game )
|
||||
<x-entry-meta-item label="Game Name" value="{{ $entry->game->name }}" />
|
||||
@endif
|
||||
@if( $entry->getRealPlatform() )
|
||||
<x-entry-meta-item label="Platform" value="{{ ($entry->getRealPlatform())->name }}" />
|
||||
@endif
|
||||
@if( $entry->game && $entry->game->genre )
|
||||
<x-entry-meta-item label="Genre" value="{{ $entry->game->genre->name }}" />
|
||||
@endif
|
||||
@if( $entry->languages->isNotEmpty() )
|
||||
<x-entry-meta-item label="Language" value="{{ $entry->languages->pluck('name')->implode(', ') }}" route="none" />
|
||||
@endif
|
||||
@if( $entry->status_id )
|
||||
<x-entry-meta-item label="Status" value="{{ $entry->status->name }}" />
|
||||
@endif
|
||||
@if( $entry->version )
|
||||
<x-entry-meta-item label="Version" value="{{ $entry->version }}" route="none" />
|
||||
@endif
|
||||
@if( $entry->release_date )
|
||||
<x-entry-meta-item label="Release Date" value="{{ $entry->release_date }}" />
|
||||
@endif
|
||||
@if( $entry->modifications->isNotEmpty() )
|
||||
<x-entry-meta-item label="Type of hack" value="{{ $entry->modifications->pluck('name')->implode(', ') }}" route="none" />
|
||||
@endif
|
||||
</div>
|
||||
<div class="hack-actions">
|
||||
<button class="btn primary">
|
||||
<i data-lucide="download"></i> Download
|
||||
</button>
|
||||
<button class="btn">
|
||||
<i data-lucide="message-square"></i> Comments
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="entry-content">
|
||||
@if( $entry->description )
|
||||
<x-entry-section-title label="Description" icon="file-text" />
|
||||
<div class="entry-description">
|
||||
{{ $entry->description }}
|
||||
</div>
|
||||
@endif
|
||||
@if( $entry->hashes->isNotEmpty() )
|
||||
<x-entry-section-title label="Hashes" icon="table-properties" />
|
||||
<div class="entry-description">
|
||||
@foreach( $entry->hashes->all() as $hash )
|
||||
Filename: {{ $hash->filename }}<br>
|
||||
CRC32: {{ $hash->hash_crc32 }}<br>
|
||||
SHA-1: {{ $hash->hash_sha1 }}<br>
|
||||
Verified: {{ $hash->verified }}<br>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@if( $entry->staff_credits )
|
||||
<h2 class="entry-section-title">
|
||||
<i data-lucide="users-round"></i> Staff credits
|
||||
</h2>
|
||||
<div class="entry-description">
|
||||
{{ $entry->staff_credits }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</article>
|
||||
@endsection
|
||||
10
resources/views/home.blade.php
Normal file
10
resources/views/home.blade.php
Normal file
@@ -0,0 +1,10 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('page-title', "Home - " . config('app.name') )
|
||||
|
||||
@section('content')
|
||||
<div class="block">
|
||||
Ceci est un block !
|
||||
</div>
|
||||
<x-error-block error-type="page-not-allowed" />
|
||||
@endsection
|
||||
34
resources/views/layouts/app.blade.php
Normal file
34
resources/views/layouts/app.blade.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@livewireStyles
|
||||
@stack('styles')
|
||||
<title>@yield('page-title', 'Romhack Plaza')</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="app">
|
||||
@include( 'components.menu' )
|
||||
|
||||
<main id="main-wrapper">
|
||||
@include('components.topbar')
|
||||
@if(session('success'))
|
||||
<x-success-block success-type="custom" :message="session('success')" />
|
||||
@endif
|
||||
@if(session('error'))
|
||||
<x-error-block error-type="custom" :message="session('error')" />
|
||||
@endif
|
||||
|
||||
<div id="content">
|
||||
@yield('content')
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
@livewireScripts
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
60
resources/views/livewire/authors-selector.blade.php
Normal file
60
resources/views/livewire/authors-selector.blade.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<div>
|
||||
<div class="form-group grid-c2">
|
||||
<div>
|
||||
@if( $newAuthor === false)
|
||||
<div class="game-selector">
|
||||
<div class="game-selector-level2">
|
||||
<x-form-field-title name="Authors" helper="Person or Group who created this, if it's you add/select yourself." required="true" />
|
||||
<input id="author-search" class="form-input" type="text" wire:model.live.debounce="search" placeholder="Search a game..." autocomplete="off"
|
||||
@focus="$wire.dropdown = $wire.search.length >= 2" @click.outside="$wire.dropdown = false" >
|
||||
</div>
|
||||
@if( $dropdown )
|
||||
<ul class="game-selector-dropdown">
|
||||
@forelse($authors as $author)
|
||||
<li>
|
||||
<button type="button" wire:click="selectAuthor({{ $author->id }}, '{{ addslashes($author->name) }}')"
|
||||
class="dropdown-item">
|
||||
<span class="dropdown-item-name">{{ $author->name }}</span>
|
||||
</button>
|
||||
</li>
|
||||
@empty
|
||||
<li class="dropdown-empty">No author found</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
@endif
|
||||
</div>
|
||||
@else
|
||||
<div class="new-author">
|
||||
<x-form-field-title name="New author" required="true" />
|
||||
<input class="form-input" wire:model="newAuthorName" type="text" autocomplete="off" value="" required>
|
||||
</div>
|
||||
@endif
|
||||
<div style="display:flex;align-items: flex-end;justify-content: right;gap:15px;margin-top:20px;">
|
||||
@if($newAuthor)
|
||||
<button type="button" class="btn primary" wire:click="addNewAuthor" :disabled="$wire.newAuthorName.trim() === ''">
|
||||
Add
|
||||
</button>
|
||||
@endif
|
||||
<button type="button" class="btn {{ $newAuthor ? '' : 'primary' }}" wire:click="switchNewAuthor">{{ $newAuthor ? "Cancel" : "Add an author" }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<x-form-field-title name="Selected authors" />
|
||||
<div class="form-group level authors-list">
|
||||
@foreach($selectedAuthors as $i => $author)
|
||||
<div class="author-item">
|
||||
<span>{{ $author['name'] }}</span>
|
||||
<button type="button" class="btn author-item-remove" wire:click="removeAuthor({{ $i }})">
|
||||
X
|
||||
</button>
|
||||
</div>
|
||||
@if( $author['id'] )
|
||||
<input type="hidden" name="authors[]" value="{{ $author['id'] }}">
|
||||
@else
|
||||
<input type="hidden" name="new-authors[]" value="{{ $author['name'] }}">
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
98
resources/views/livewire/game-selector.blade.php
Normal file
98
resources/views/livewire/game-selector.blade.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<div x-data='GameSelector()' x-init="init({
|
||||
name: @json(old('new-game-title') ?: null),
|
||||
platformId: @json(old('new-game-platform') ? (string) old('new-game-platform') : null),
|
||||
genreId: @json(old('new-game-genre') ? (string) old('new-game-genre') : null)
|
||||
})">
|
||||
{{--
|
||||
Prefill if server-side error.
|
||||
--}}
|
||||
<div class="form-group grid-c3">
|
||||
|
||||
@if( !$newGame && !$hasOldNewGame )
|
||||
{{-- Search game mode --}}
|
||||
<div class="game-selector">
|
||||
<div class="game-selector-level2">
|
||||
|
||||
<x-form-field-title name="Game" required="true" />
|
||||
<input class="form-input" type="text" wire:model.live.debounce="search" placeholder="Search a game..." autocomplete="off"
|
||||
@focus="$wire.dropdown = $wire.search.length >= {{ $required_chars }}" @click.outside="$wire.dropdown = false" >
|
||||
|
||||
<input type="hidden" name="game_id" value="{{ $gameId ?? '' }}" />
|
||||
|
||||
</div>
|
||||
|
||||
@if( $dropdown )
|
||||
{{-- List games --}}
|
||||
<ul class="game-selector-dropdown">
|
||||
@forelse($games as $game)
|
||||
<li>
|
||||
<button type="button" wire:click="selectGame({{ $game->id }}, '{{ addslashes($game->name) }}')"
|
||||
class="dropdown-item" {{ $gameId === $game->id ? 'selected' : '' }} >
|
||||
<span class="dropdown-item-name">{{ $game->name }}</span>
|
||||
@if($game->platform)
|
||||
<span class="badge">{{ $game->platform->short_name }}</span>
|
||||
@endif
|
||||
@if($game->genre)
|
||||
<span class="badge">{{ $game->genre->name }}</span>
|
||||
@endif
|
||||
</button>
|
||||
</li>
|
||||
@empty
|
||||
<li class="dropdown-empty">No games found</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
<div class="platform-prefilled">
|
||||
<x-form-field-title name="Platform" helper="Prefilled" />
|
||||
<input class="form-input" disabled="disabled" type="text" autocomplete="off" value="{{ $platformName }}">
|
||||
</div>
|
||||
|
||||
<div class="genre-prefilled">
|
||||
<x-form-field-title name="Genre" helper="Prefilled" />
|
||||
<input class="form-input" disabled="disabled" type="text" autocomplete="off" value="{{ $genreName }}" >
|
||||
</div>
|
||||
|
||||
@else {{-- New game --}}
|
||||
|
||||
<div class="new-game-title">
|
||||
<x-form-field-title name="Game" required="true" />
|
||||
<input class="form-input" name="new-game-title" type="text" autocomplete="off" x-model="name" value="{{ old('new-game-title', '') }}" required>
|
||||
</div>
|
||||
|
||||
<div class="new-game-platform">
|
||||
<x-form-field-title name="Platform" required="true" />
|
||||
<select class="form-select" name="new-game-platform" x-model="platformId" required>
|
||||
<option value="" disabled>---</option>
|
||||
@foreach( $platforms as $platform )
|
||||
<option value="{{ (string) $platform->id }}">{{ $platform->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="new-game-genre">
|
||||
<x-form-field-title name="Genre" required="true" />
|
||||
<select class="form-select" name="new-game-genre" x-model="genreId" required>
|
||||
<option value="" disabled>---</option>
|
||||
@foreach( $genres as $genre )
|
||||
<option value="{{ (string) $genre->id }}">{{ $genre->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div style="display:flex;align-items: flex-end;justify-content: right;gap:15px;">
|
||||
@if($gameId)
|
||||
<button type="button" class="btn" wire:click="clearGame">
|
||||
Remove
|
||||
</button>
|
||||
@endif
|
||||
<button type="button" class="btn primary" wire:click="switchNewGame">{{ $newGame ? "Cancel" : "Add a game" }}</button>
|
||||
</div>
|
||||
</div>
|
||||
66
resources/views/livewire/hashes-upload.blade.php
Normal file
66
resources/views/livewire/hashes-upload.blade.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<div x-data="HashesManager($wire)" x-ref="hashRoot">
|
||||
<x-form-field-title name="Hashes" required="true" />
|
||||
@if( count( $hashes ) > 0)
|
||||
<div class="form-group grid-hashes">
|
||||
|
||||
<div class="hash-filename">
|
||||
<x-form-field-title name="Filename" />
|
||||
</div>
|
||||
|
||||
<div class="hash-crc32">
|
||||
<x-form-field-title name="CRC32" />
|
||||
</div>
|
||||
|
||||
<div class="hash-sha1">
|
||||
<x-form-field-title name="SHA-1" />
|
||||
</div>
|
||||
|
||||
<div class="hash-verified">
|
||||
<x-form-field-title name="Verified" />
|
||||
</div>
|
||||
|
||||
<div class="hash-remove">
|
||||
<x-form-field-title name="Actions" />
|
||||
|
||||
</div>
|
||||
|
||||
@foreach( $hashes as $i => $hash )
|
||||
<div class="hash-filename">
|
||||
<input class="form-input" type="text" autocomplete="off" value="{{ $hash['filename'] }}" disabled>
|
||||
</div>
|
||||
<div class="hash-crc32">
|
||||
<input class="form-input" type="text" autocomplete="off" value="{{ $hash['hash_crc32'] }}" disabled>
|
||||
</div>
|
||||
<div class="hash-sha1">
|
||||
<input class="form-input" type="text" autocomplete="off" value="{{ $hash['hash_sha1'] }}" disabled>
|
||||
</div>
|
||||
<div class="hash-verified">
|
||||
<input class="form-input" type="text" autocomplete="off" value="{{ $hash['verified'] }}" disabled>
|
||||
</div>
|
||||
<div class="hash-remove">
|
||||
<button type="button" class="btn" wire:click="removeHash({{ $i }})">
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="hashes[{{ $i }}][filename]" value="{{ $hash['filename'] }}">
|
||||
<input type="hidden" name="hashes[{{ $i }}][hash_crc32]" value="{{ $hash['hash_crc32'] }}">
|
||||
<input type="hidden" name="hashes[{{ $i }}][hash_sha1]" value="{{ $hash['hash_sha1'] }}">
|
||||
<input type="hidden" name="hashes[{{ $i }}][verified]" value="{{ $hash['verified'] }}">
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div style="display:flex;align-items: flex-end;justify-content: right;gap:15px;">
|
||||
<span x-show="isCalculating" x-cloak>
|
||||
<i data-lucide="loader-2" class="spin"></i>
|
||||
Please wait...
|
||||
</span>
|
||||
|
||||
<span x-show="error" x-text="error" class="form-error-text" x-cloak></span>
|
||||
|
||||
<button type="button" class="btn primary" :disabled="isCalculating" @click="handleSubmitFile()">Add Hashes</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
7
resources/views/pages/forbidden.blade.php
Normal file
7
resources/views/pages/forbidden.blade.php
Normal file
@@ -0,0 +1,7 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('page-title', "Forbidden - " . config('app.name') )
|
||||
|
||||
@section('content')
|
||||
<x-error-block error-type="page-not-allowed" message="{{ $permission }}" />
|
||||
@endsection
|
||||
9
resources/views/submissions/create.blade.php
Normal file
9
resources/views/submissions/create.blade.php
Normal file
@@ -0,0 +1,9 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('page-title', "Submit - " . config('app.name') )
|
||||
|
||||
@section('content')
|
||||
{{ \Diglactic\Breadcrumbs\Breadcrumbs::render() }}
|
||||
<div class="page-title">{{ $words['page_title'] }}</div>
|
||||
@include('submissions.form')
|
||||
@endsection
|
||||
9
resources/views/submissions/edit.blade.php
Normal file
9
resources/views/submissions/edit.blade.php
Normal file
@@ -0,0 +1,9 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('page-title', "Edit $entry->title - " . config('app.name') )
|
||||
|
||||
@section('content')
|
||||
{{ \Diglactic\Breadcrumbs\Breadcrumbs::render() }}
|
||||
<div class="page-title">{{ $words['page_title'] }}</div>
|
||||
@include('submissions.form')
|
||||
@endsection
|
||||
172
resources/views/submissions/form.blade.php
Normal file
172
resources/views/submissions/form.blade.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/** @var \App\Models\Modification $modif */
|
||||
/** @var \App\Models\Status $status */
|
||||
?>
|
||||
|
||||
{{-- Pushed in header. --}}
|
||||
@push('styles')
|
||||
<meta name="fs-section" content="{{ $section }}">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<meta name="submission-has-errors" content="{{ $errors->any() ? '1' : '0' }}">
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
@vite('resources/js/submissions.js')
|
||||
@endpush
|
||||
|
||||
{{-- Server side errors summary --}}
|
||||
@if($errors->any())
|
||||
@foreach( $errors->all() as $error )
|
||||
<x-form-error-text message="{{ $error }}" />
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
<div class="block">
|
||||
<form action="{{ $isEdit ? route('submit.update', [ $section, $entry->id ] ) : route('submit.store', $section ) }}"
|
||||
method="POST" x-data="Submission()" x-init="init()" @submit.prevent="submitForm($event)">
|
||||
@include('submissions.fs-upload')
|
||||
|
||||
<!-- ABOUT THE ENTRY -->
|
||||
<x-form-group-title label="{{ $words['about_the'] }}" icon="puzzle" />
|
||||
|
||||
@if( section_must_not_be( 'translations', $section ) )
|
||||
<div class="form-group">
|
||||
<x-form-field-title name="{{ $words['entry_title'] }}" required="true" />
|
||||
<input class="form-input" type="text" name="entry_title" value="{{ old('entry_title', $entry->title ?? '' ) }}" required>
|
||||
@error('entry_title')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
</div>
|
||||
@else
|
||||
<div class="form-group">
|
||||
<x-form-field-title name="{{ $words['entry_title'] }}" helper="{{ $words['entry_title_helper'] }}" />
|
||||
<input class="form-input" type="text" name="entry_title" value="{{ old('entry_title', $entry->title, '' ) }}">
|
||||
@error('entry_title')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if( section_must_be( 'romhacks', $section ) )
|
||||
<div class="form-group">
|
||||
<x-form-field-title name="{{ $words['type_of_hack'] }}" required="true" />
|
||||
<div class="form-type-of-checkboxes form-group level" id="modifications-group" x-ref="modificationsGroup">
|
||||
@foreach( $modifications as $modif )
|
||||
<label><input class="form-checkbox" type="checkbox" name="modifications[]" value="{{ $modif->id }}" {{ in_array($modif->id, $oldModifications) ? 'checked' : '' }}>{{ $modif->name }}</label>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="form-error-text" x-show="errorKey === 'noModifications'" x-text="errorMessage"></div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if( section_must_be( ['romhacks', 'translations'], $section ) )
|
||||
<div class="form-group grid-c3">
|
||||
<div>
|
||||
<x-form-field-title name="{{ $words['version'] }}" required="true" />
|
||||
<input class="form-input" type="text" name="version" value="{{ old( 'version', $entry->version ?? '' ) }}" required>
|
||||
</div>
|
||||
<div>
|
||||
<x-form-field-title name="{{ $words['release_date'] }}" helper="{{ $words['release_date_helper'] }}" required="true" />
|
||||
{{-- TODO: Add max to the date --}}
|
||||
<input type="date" class="form-input" name="release-date" value="{{ old('release-date') ?? $entry->release_date?->format('Y-m-d') ?? '' }}" required>
|
||||
</div>
|
||||
<div>
|
||||
<x-form-field-title name="{{ $words['status'] }}" required="true" />
|
||||
<div class="form-status-radio form-group level">
|
||||
@foreach( $statuses as $status )
|
||||
<label><input class="form-radio" type="radio" name="status" value="{{ $status->id }}" {{ old('status', $entry->status_id ) == $status->id ? 'checked' : '' }} required>{{ $status->name }}</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if( section_must_be( 'translations', $section ) )
|
||||
<x-form-field-title name="Languages" required="true" />
|
||||
<x-languages-selector :selected="$oldLanguages" />
|
||||
@endif
|
||||
|
||||
<div class="form-group" x-ref="descriptionField">
|
||||
<x-form-field-title name="{{ $words['description'] }}" required="true" />
|
||||
<x-markdown-textarea name="description" value="{{ old('description', $entry->description ?? '') }}" />
|
||||
<div class="form-error-text" x-show="errorKey === 'noDescription'" x-text="errorMessage"></div>
|
||||
@error('description')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<x-form-group-title label="{{ $words['about_game'] }}" icon="gamepad-2" />
|
||||
<div x-ref="gameSelector">
|
||||
<livewire:game-selector
|
||||
:game-id="old('game_id', $entry->game_id ?? null )"
|
||||
:new-game-title="old('new-game-title')"
|
||||
:new-game-platform="old('new-game-platform')"
|
||||
:new-game-genre="old('new-game-genre')"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-error-text" x-show="errorKey === 'noGame'" x-text="errorMessage"></div>
|
||||
@error('game_id')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
@error('new-game-title')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
@error('new-game-platform')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
@error('new-game-genre')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
<livewire:hashes-upload :old-hashes="old('hashes', $entry->hashes->toArray(), [])" />
|
||||
|
||||
@if( section_must_not_be( 'translations', $section ) )
|
||||
<x-form-field-title name="Languages" required="true" />
|
||||
<x-languages-selector :selected="$oldLanguages" />
|
||||
@error('languages')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
@error('languages.*')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
@endif
|
||||
|
||||
<x-form-group-title label="{{ $words['attachments'] }}" icon="paperclip" />
|
||||
<x-main-image-field :old-path="old('main-image', $entry->main_image ?? '')" />
|
||||
<x-gallery-field :old-paths="old('gallery', $entry->gallery->pluck('image')->toArray() ?? [] )"/>
|
||||
@error('gallery')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
@error('gallery.*')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
|
||||
<x-form-group-title label="{{ $words['authors'] }}" icon="users" />
|
||||
<livewire:authors-selector :old-authors="old('authors', $entry->authors->map(fn($a) => ['id' => $a->id, 'name' => $a->name ])->toArray() ?? [])" :old-new-authors="old('new-authors', [])" />
|
||||
@error('authors')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
@error('new-authors')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
<x-staff-credits-field :old-staff-credits="old('staff_credits', $entry->staff_credits ?? null)" />
|
||||
|
||||
<x-form-group-title label="{{ $words['related_links'] }}" icon="link" />
|
||||
<div class="form-group grid-c2">
|
||||
<div>
|
||||
<x-form-field-title name="{{ $words['release_site'] }}" helper="{{ $words['release_site_helper'] }}" required="" />
|
||||
<input class="form-input" type="url" name="release_site" value="{{ old( 'release_site', $entry->relevant_link ?? '' ) }}">
|
||||
</div>
|
||||
<div>
|
||||
<x-form-field-title name="{{ $words['youtube_video'] }}" required="" />
|
||||
<input class="form-input" type="url" name="youtube_video" value="{{ old( 'youtube_video', $entry->youtube_link ?? '' ) }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@csrf
|
||||
|
||||
<div class="submit">
|
||||
<x-submit-entry-status :section="$section" />
|
||||
<button id="submit-button" type="submit" class="btn primary" style="padding:1%;">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
69
resources/views/submissions/fs-upload.blade.php
Normal file
69
resources/views/submissions/fs-upload.blade.php
Normal file
@@ -0,0 +1,69 @@
|
||||
{{-- File Server uploader import --}}
|
||||
<div class="form-group level" x-data="FSUploader()" x-init="init(@js($oldFilesArray))">
|
||||
|
||||
<x-form-group-title label="Download Files" icon="upload-cloud" />
|
||||
<div class="form-group">
|
||||
<x-form-field-title name="Files" helper="test" required="true" />
|
||||
<div class="form-upload" x-ref="uploadTarget" :class="{ 'disabled': isUploading }">
|
||||
<input type="file" multiple :disabled="isUploading" @change="handleSubmitFile($event)">
|
||||
<div class="form-upload-placeholder level">
|
||||
<i data-lucide="file-archive" size="36" style="margin-bottom:15px;color:var(--text2)"></i>
|
||||
<div style="font-size: 1.1rem;color:var(--text);margin-bottom:5px;">
|
||||
Click or drag'n drop files here.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<x-form-error-text message="Don't submit ROMs" />
|
||||
|
||||
{{-- Client-side Errors --}}
|
||||
<div class="form-error-text" x-show="errorKey === 'noFiles' || errorKey === 'uploadError' || errorKey === 'notAllFilesDone'" x-text="errorMessage"></div>
|
||||
|
||||
{{-- Server-side Errors --}}
|
||||
@error('file_ids')
|
||||
<x-form-error-text message="{{ $message }}" />
|
||||
@enderror
|
||||
|
||||
</div>
|
||||
|
||||
{{--
|
||||
File listing. Used for editions or server-side errors.
|
||||
--}}
|
||||
<div class="upload-list" x-show="numberOfFiles > 0" x-cloak>
|
||||
<template x-for="(file,i) in files" :key="i">
|
||||
<div class="upload-item" :class="
|
||||
{
|
||||
'upload-item-uploading': !file.done && !file.error,
|
||||
'upload-item-done': file.done,
|
||||
'upload-item-error': file.error
|
||||
}">
|
||||
<template x-if="!file.done && !file.error">
|
||||
<i data-lucide="loader-2" class="spin"></i>
|
||||
</template>
|
||||
<template x-if="file.done">
|
||||
<i data-lucide="check-circle"></i>
|
||||
</template>
|
||||
<template x-if="file.error">
|
||||
<i data-lucide="alert-circle"></i>
|
||||
</template>
|
||||
|
||||
<div class="upload-item-info">
|
||||
<span class="upload-item-name" x-text="file.name"></span>
|
||||
<div class="progress" x-show="!file.done && !file.error">
|
||||
<div class="progress-bar" :style="{width: file.progressValue + '%' }">
|
||||
<span class="progress-bar-label" x-text="file.progressValue + '% - chunk' + file.currentChunk + ' / ' + file.totalChunks"></span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="upload-item-error" x-show="file.error" x-text="file.error"></span>
|
||||
</div>
|
||||
<div class="upload-item-actions">
|
||||
<button type="button" class="btn" x-show="file.error" @click="handleRetryFile(i)">
|
||||
<i data-lucide="refresh-cw"></i>
|
||||
</button>
|
||||
<button type="button" class="btn" x-show="file.done || file.error" @click="handleRemoveFile(i)">
|
||||
<i data-lucide="x"></i>
|
||||
</button>
|
||||
</div>
|
||||
<input type="hidden" name="files_uuid[]" :value="file.uuid" x-show="file.done">
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
223
resources/views/welcome.blade.php
Normal file
223
resources/views/welcome.blade.php
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user