summaryrefslogtreecommitdiff
path: root/resources
diff options
context:
space:
mode:
Diffstat (limited to 'resources')
-rw-r--r--resources/js/app.js1
-rw-r--r--resources/js/bootstrap.js41
-rw-r--r--resources/lang/en/auth.php19
-rw-r--r--resources/lang/en/pagination.php19
-rw-r--r--resources/lang/en/passwords.php22
-rw-r--r--resources/lang/en/validation.php151
-rw-r--r--resources/sass/_background.scss26
-rw-r--r--resources/sass/_navbar.scss20
-rw-r--r--resources/sass/_utility.scss25
-rw-r--r--resources/sass/_variables.scss19
-rw-r--r--resources/sass/app.scss28
-rw-r--r--resources/views/about.blade.php86
-rw-r--r--resources/views/auth/login.blade.php73
-rw-r--r--resources/views/auth/passwords/confirm.blade.php49
-rw-r--r--resources/views/auth/passwords/email.blade.php47
-rw-r--r--resources/views/auth/passwords/reset.blade.php65
-rw-r--r--resources/views/auth/register.blade.php77
-rw-r--r--resources/views/auth/verify.blade.php28
-rw-r--r--resources/views/cinema-show.blade.php150
-rw-r--r--resources/views/cinema.blade.php174
-rw-r--r--resources/views/home.blade.php23
-rw-r--r--resources/views/index.blade.php49
-rw-r--r--resources/views/layouts/app.blade.php178
-rw-r--r--resources/views/layouts/footer-style.blade.php14
-rw-r--r--resources/views/layouts/footer.blade.php18
-rw-r--r--resources/views/list.blade.php177
-rw-r--r--resources/views/search.blade.php19
-rw-r--r--resources/views/topicindex.blade.php50
-rw-r--r--resources/views/topicpopular.blade.php48
-rw-r--r--resources/views/welcome.blade.php100
30 files changed, 1796 insertions, 0 deletions
diff --git a/resources/js/app.js b/resources/js/app.js
new file mode 100644
index 0000000..40c55f6
--- /dev/null
+++ b/resources/js/app.js
@@ -0,0 +1 @@
+require('./bootstrap');
diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js
new file mode 100644
index 0000000..8eaba1b
--- /dev/null
+++ b/resources/js/bootstrap.js
@@ -0,0 +1,41 @@
+window._ = require('lodash');
+
+/**
+ * We'll load jQuery and the Bootstrap jQuery plugin which provides support
+ * for JavaScript based Bootstrap features such as modals and tabs. This
+ * code may be modified to fit the specific needs of your application.
+ */
+
+try {
+ window.Popper = require('popper.js').default;
+ window.$ = window.jQuery = require('jquery');
+
+ require('bootstrap');
+} catch (e) {}
+
+/**
+ * We'll load the axios HTTP library which allows us to easily issue requests
+ * to our Laravel back-end. This library automatically handles sending the
+ * CSRF token as a header based on the value of the "XSRF" token cookie.
+ */
+
+window.axios = require('axios');
+
+window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
+
+/**
+ * Echo exposes an expressive API for subscribing to channels and listening
+ * for events that are broadcast by Laravel. Echo and event broadcasting
+ * allows your team to easily build robust real-time web applications.
+ */
+
+// import Echo from 'laravel-echo';
+
+// window.Pusher = require('pusher-js');
+
+// window.Echo = new Echo({
+// broadcaster: 'pusher',
+// key: process.env.MIX_PUSHER_APP_KEY,
+// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
+// encrypted: true
+// });
diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php
new file mode 100644
index 0000000..e5506df
--- /dev/null
+++ b/resources/lang/en/auth.php
@@ -0,0 +1,19 @@
+<?php
+
+return [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Authentication Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are used during authentication for various
+ | messages that we need to display to the user. You are free to modify
+ | these language lines according to your application's requirements.
+ |
+ */
+
+ 'failed' => 'These credentials do not match our records.',
+ 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
+
+];
diff --git a/resources/lang/en/pagination.php b/resources/lang/en/pagination.php
new file mode 100644
index 0000000..d481411
--- /dev/null
+++ b/resources/lang/en/pagination.php
@@ -0,0 +1,19 @@
+<?php
+
+return [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Pagination Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are used by the paginator library to build
+ | the simple pagination links. You are free to change them to anything
+ | you want to customize your views to better match your application.
+ |
+ */
+
+ 'previous' => '&laquo; Previous',
+ 'next' => 'Next &raquo;',
+
+];
diff --git a/resources/lang/en/passwords.php b/resources/lang/en/passwords.php
new file mode 100644
index 0000000..2345a56
--- /dev/null
+++ b/resources/lang/en/passwords.php
@@ -0,0 +1,22 @@
+<?php
+
+return [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Password Reset Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are the default lines which match reasons
+ | that are given by the password broker for a password update attempt
+ | has failed, such as for an invalid token or invalid new password.
+ |
+ */
+
+ 'reset' => 'Your password has been reset!',
+ 'sent' => 'We have emailed your password reset link!',
+ 'throttled' => 'Please wait before retrying.',
+ 'token' => 'This password reset token is invalid.',
+ 'user' => "We can't find a user with that email address.",
+
+];
diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php
new file mode 100644
index 0000000..a65914f
--- /dev/null
+++ b/resources/lang/en/validation.php
@@ -0,0 +1,151 @@
+<?php
+
+return [
+
+ /*
+ |--------------------------------------------------------------------------
+ | Validation Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines contain the default error messages used by
+ | the validator class. Some of these rules have multiple versions such
+ | as the size rules. Feel free to tweak each of these messages here.
+ |
+ */
+
+ 'accepted' => 'The :attribute must be accepted.',
+ 'active_url' => 'The :attribute is not a valid URL.',
+ 'after' => 'The :attribute must be a date after :date.',
+ 'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
+ 'alpha' => 'The :attribute may only contain letters.',
+ 'alpha_dash' => 'The :attribute may only contain letters, numbers, dashes and underscores.',
+ 'alpha_num' => 'The :attribute may only contain letters and numbers.',
+ 'array' => 'The :attribute must be an array.',
+ 'before' => 'The :attribute must be a date before :date.',
+ 'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
+ 'between' => [
+ 'numeric' => 'The :attribute must be between :min and :max.',
+ 'file' => 'The :attribute must be between :min and :max kilobytes.',
+ 'string' => 'The :attribute must be between :min and :max characters.',
+ 'array' => 'The :attribute must have between :min and :max items.',
+ ],
+ 'boolean' => 'The :attribute field must be true or false.',
+ 'confirmed' => 'The :attribute confirmation does not match.',
+ 'date' => 'The :attribute is not a valid date.',
+ 'date_equals' => 'The :attribute must be a date equal to :date.',
+ 'date_format' => 'The :attribute does not match the format :format.',
+ 'different' => 'The :attribute and :other must be different.',
+ 'digits' => 'The :attribute must be :digits digits.',
+ 'digits_between' => 'The :attribute must be between :min and :max digits.',
+ 'dimensions' => 'The :attribute has invalid image dimensions.',
+ 'distinct' => 'The :attribute field has a duplicate value.',
+ 'email' => 'The :attribute must be a valid email address.',
+ 'ends_with' => 'The :attribute must end with one of the following: :values.',
+ 'exists' => 'The selected :attribute is invalid.',
+ 'file' => 'The :attribute must be a file.',
+ 'filled' => 'The :attribute field must have a value.',
+ 'gt' => [
+ 'numeric' => 'The :attribute must be greater than :value.',
+ 'file' => 'The :attribute must be greater than :value kilobytes.',
+ 'string' => 'The :attribute must be greater than :value characters.',
+ 'array' => 'The :attribute must have more than :value items.',
+ ],
+ 'gte' => [
+ 'numeric' => 'The :attribute must be greater than or equal :value.',
+ 'file' => 'The :attribute must be greater than or equal :value kilobytes.',
+ 'string' => 'The :attribute must be greater than or equal :value characters.',
+ 'array' => 'The :attribute must have :value items or more.',
+ ],
+ 'image' => 'The :attribute must be an image.',
+ 'in' => 'The selected :attribute is invalid.',
+ 'in_array' => 'The :attribute field does not exist in :other.',
+ 'integer' => 'The :attribute must be an integer.',
+ 'ip' => 'The :attribute must be a valid IP address.',
+ 'ipv4' => 'The :attribute must be a valid IPv4 address.',
+ 'ipv6' => 'The :attribute must be a valid IPv6 address.',
+ 'json' => 'The :attribute must be a valid JSON string.',
+ 'lt' => [
+ 'numeric' => 'The :attribute must be less than :value.',
+ 'file' => 'The :attribute must be less than :value kilobytes.',
+ 'string' => 'The :attribute must be less than :value characters.',
+ 'array' => 'The :attribute must have less than :value items.',
+ ],
+ 'lte' => [
+ 'numeric' => 'The :attribute must be less than or equal :value.',
+ 'file' => 'The :attribute must be less than or equal :value kilobytes.',
+ 'string' => 'The :attribute must be less than or equal :value characters.',
+ 'array' => 'The :attribute must not have more than :value items.',
+ ],
+ 'max' => [
+ 'numeric' => 'The :attribute may not be greater than :max.',
+ 'file' => 'The :attribute may not be greater than :max kilobytes.',
+ 'string' => 'The :attribute may not be greater than :max characters.',
+ 'array' => 'The :attribute may not have more than :max items.',
+ ],
+ 'mimes' => 'The :attribute must be a file of type: :values.',
+ 'mimetypes' => 'The :attribute must be a file of type: :values.',
+ 'min' => [
+ 'numeric' => 'The :attribute must be at least :min.',
+ 'file' => 'The :attribute must be at least :min kilobytes.',
+ 'string' => 'The :attribute must be at least :min characters.',
+ 'array' => 'The :attribute must have at least :min items.',
+ ],
+ 'not_in' => 'The selected :attribute is invalid.',
+ 'not_regex' => 'The :attribute format is invalid.',
+ 'numeric' => 'The :attribute must be a number.',
+ 'password' => 'The password is incorrect.',
+ 'present' => 'The :attribute field must be present.',
+ 'regex' => 'The :attribute format is invalid.',
+ 'required' => 'The :attribute field is required.',
+ 'required_if' => 'The :attribute field is required when :other is :value.',
+ 'required_unless' => 'The :attribute field is required unless :other is in :values.',
+ 'required_with' => 'The :attribute field is required when :values is present.',
+ 'required_with_all' => 'The :attribute field is required when :values are present.',
+ 'required_without' => 'The :attribute field is required when :values is not present.',
+ 'required_without_all' => 'The :attribute field is required when none of :values are present.',
+ 'same' => 'The :attribute and :other must match.',
+ 'size' => [
+ 'numeric' => 'The :attribute must be :size.',
+ 'file' => 'The :attribute must be :size kilobytes.',
+ 'string' => 'The :attribute must be :size characters.',
+ 'array' => 'The :attribute must contain :size items.',
+ ],
+ 'starts_with' => 'The :attribute must start with one of the following: :values.',
+ 'string' => 'The :attribute must be a string.',
+ 'timezone' => 'The :attribute must be a valid zone.',
+ 'unique' => 'The :attribute has already been taken.',
+ 'uploaded' => 'The :attribute failed to upload.',
+ 'url' => 'The :attribute format is invalid.',
+ 'uuid' => 'The :attribute must be a valid UUID.',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify custom validation messages for attributes using the
+ | convention "attribute.rule" to name the lines. This makes it quick to
+ | specify a specific custom language line for a given attribute rule.
+ |
+ */
+
+ 'custom' => [
+ 'attribute-name' => [
+ 'rule-name' => 'custom-message',
+ ],
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Attributes
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are used to swap our attribute placeholder
+ | with something more reader friendly such as "E-Mail Address" instead
+ | of "email". This simply helps us make our message more expressive.
+ |
+ */
+
+ 'attributes' => [],
+
+];
diff --git a/resources/sass/_background.scss b/resources/sass/_background.scss
new file mode 100644
index 0000000..452d4d2
--- /dev/null
+++ b/resources/sass/_background.scss
@@ -0,0 +1,26 @@
+html {
+ height: 100%;
+}
+
+body {
+ width: 100%;
+ height: auto;
+ min-height:35rem;
+ background: linear-gradient(to bottom, rgba(1,1,1,.25) 0%, rgba(1,1,1,.45) 90%, rgba(2, 11, 26, 0.65) 100%), url("/img/world-bg.jpg");
+ background-color: rgba(2, 11, 26, 0.65);
+ background-position: center;
+ background-repeat: no-repeat;
+ background-attachment: scroll;
+ background-size: cover;
+}
+.cover-container {
+ color: white;
+ max-width: 42em;
+}
+.cover {
+ padding: 0 1.5rem;
+}
+.cover .btn-lg {
+ padding: .75rem 1.25rem;
+ font-weight: 700;
+}
diff --git a/resources/sass/_navbar.scss b/resources/sass/_navbar.scss
new file mode 100644
index 0000000..4645fa5
--- /dev/null
+++ b/resources/sass/_navbar.scss
@@ -0,0 +1,20 @@
+.navbar {
+ background-color: rgba(0,0,0,0) !important;
+}
+.navbar-toggler {
+ border-color: #808080;
+}
+
+.navbar-dark .nav-link {
+ color: darken( #fff, 10% ) !important;
+}
+
+@media( min-width: 768px ) {
+ .navbar-searchform {
+ margin-left: 0.5rem;
+ }
+}
+
+.nav-link:hover {
+ text-decoration: underline !important;
+}
diff --git a/resources/sass/_utility.scss b/resources/sass/_utility.scss
new file mode 100644
index 0000000..bcc163d
--- /dev/null
+++ b/resources/sass/_utility.scss
@@ -0,0 +1,25 @@
+.text-lg {
+ font-size:1.125rem;
+}
+hr {
+ width: 100%;
+ color: white;
+ background-color: white;
+ height: 1px;
+ margin-top: inherit;
+}
+.mt-20 {
+ margin-top: 20px;
+}
+.mt-30 {
+ margin-top: 30px;
+}
+.mt-35 {
+ margin-top: 35px;
+}
+.mt-40 {
+ margin-top: 40px;
+}
+.mt-50 {
+ margin-top: 50px;
+}
diff --git a/resources/sass/_variables.scss b/resources/sass/_variables.scss
new file mode 100644
index 0000000..0407ab5
--- /dev/null
+++ b/resources/sass/_variables.scss
@@ -0,0 +1,19 @@
+// Body
+$body-bg: #f8fafc;
+
+// Typography
+$font-family-sans-serif: 'Nunito', sans-serif;
+$font-size-base: 0.9rem;
+$line-height-base: 1.6;
+
+// Colors
+$blue: #3490dc;
+$indigo: #6574cd;
+$purple: #9561e2;
+$pink: #f66d9b;
+$red: #e3342f;
+$orange: #f6993f;
+$yellow: #ffed4a;
+$green: #38c172;
+$teal: #4dc0b5;
+$cyan: #6cb2eb;
diff --git a/resources/sass/app.scss b/resources/sass/app.scss
new file mode 100644
index 0000000..7111267
--- /dev/null
+++ b/resources/sass/app.scss
@@ -0,0 +1,28 @@
+// Fonts
+@import url('https://fonts.googleapis.com/css?family=Nunito');
+
+// Variables
+@import 'variables';
+
+// Bootstrap
+@import '~bootstrap/scss/bootstrap';
+
+@import 'background';
+@import 'navbar';
+@import 'utility';
+
+.hn {
+ display: inline-block;
+ font-size: inherit;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -.125em;
+ fill: #ff6600;
+}
+.mastodon {
+ display: inline-block;
+ font-size: inherit;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -.125em;
+}
diff --git a/resources/views/about.blade.php b/resources/views/about.blade.php
new file mode 100644
index 0000000..dd1d848
--- /dev/null
+++ b/resources/views/about.blade.php
@@ -0,0 +1,86 @@
+@extends('layouts.app')
+
+@section('styles')
+html {
+ height: 100%;
+}
+@endsection
+
+@section('content')
+ <div style="margin-top: 20px" class="container">
+
+ <div class="card">
+ <h1 class="card-header">
+ More about <strong>{{ env('APP_NAME') }}</strong>
+ </h1>
+ <div class="card-body">
+ <p class="card-text">
+ This website index and curates automatically "good" articles from Wikipedia.
+
+<br>
+<br>
+
+It does so by fetching the <a href="https://news.ycombinator.com">{!! file_get_contents(public_path() . "/img/y-combinator.svg") !!} Hacker News (HN)</a> API and checking for a specific threshold. The idea is that an article is good, when it is posted to and discussed on HN. And it is even better when it is more often posted and/or sparked a great discussion. To get the best out of it this website links back to every worthy discussion, hence the name.
+
+<br>
+<br>
+
+Furthermore, it structures the articles and categorizes them in topics. You can find the respective topics above the article, or <a href="{{ route('topic_index') }}">click here</a> to see all topics alphabetically listed and <a href="{{ route('popular_topics') }}">here to see</a> them sorted by popularity. The topics above the article (those little blue pills) are clickable and link to other articles with the same topic. Those topics are not verbatim copied from the Wikipedia page, but created a custom way. And I may be biased, but I find them far more useful than the categories Wikipedia thinks those articles are in. "English poetry in 1751"? Yeah, sure, that's <em>very</em> specific.
+
+<br>
+<br>
+
+For starters I recommend to start with the <a href="{{ route('popular') }}">most popular articles</a> and then go through the stack, or browse the <a href="{{ route('popular_topics') }}">most popular topics</a>. If you are a seasoned reader consider the <a href="{{ route('new') }}">'New' site</a> for newly added articles or the <a href="{{ route('random') }}">'Random' button</a> above, which brings some real gems to light.
+
+<br>
+<br>
+
+If you have feedback, want to report a bug or just say hello, hit me up by e-mail: <em>hi @ thisdomain without the www .com</em>
+
+<br>
+<br>
+You can now also follow on Mastodon <a title="Follow on Mastodon {{ env('MASTODON_HANDLE') }}" href="{{ env('MASTODON_URL') }}" target=_blank>{!! file_get_contents(public_path() . "/img/mastodon.svg") !!} @MostDiscussed</a> to stay up to date.
+
+<h2>📈 Meanwhile: <strong>Stats!</strong></h2>
+
+Indexed articles: <strong>{{ $count_articles }}</strong>
+<br>
+Discussions on HN: <strong>{{ $count_discussions }} </strong>
+<br>
+Sum of all comments: <strong>{{ $count_comments}} </strong>
+<br>
+Sum of all upvotes: <strong>{{ $count_upvotes }} </strong> (...soo much internet juice 🤤)
+<br>
+<br>
+Keep reading!
+
+
+<!--
+ I was curious what HN may find interesting, so I used upvoted or discussed articles from Wikipedia as a proxy and build this. All articles are <a href="{{ route('popular_topics') }}">structured and categorized</a> to get a better overview. Unsurprisingly <a href="{{ route('topic', 'computing') }}">computing</a> was on the top, but then it might get interesting.
+ <br>
+ <br>
+ So I keep this as a resource of curious, obscure, inspiring and interesting bits and insights.
+ Other way to phrase it: Reading Wikipedia was my hobby, so I automated it. (Sure, what else.)
+ <br>
+ <br>
+ Enter <a href="{{ route('index') }}">mostdiscussed.com</a>. This is a collection of curated Wikipedia articles, sourced primarily (for now) from <a href="https://news.ycombinator.com">{!! file_get_contents(public_path() . "/img/y-combinator.svg") !!} Hacker News</a>. For structured consuming most of them are further categorized in topics. For starting, I recommend <a href="{{ route('popular') }}">reading the most popular articles</a> or <a href="{{ route('popular_topics') }}">browse by topics</a>.-->
+ </p>
+ </div>
+ </div>
+<!--
+ <div style="margin-bottom: 20px"></div>
+
+ <div class="card">
+ <h1 class="card-header">
+ </h1>
+ <div class="card-body">
+ <p class="card-text">
+ </p>
+ </div>
+ </div>
+
+ <div style="margin-bottom: 20px"></div>
+
+-->
+ </div>
+@endsection
diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php
new file mode 100644
index 0000000..c12b97e
--- /dev/null
+++ b/resources/views/auth/login.blade.php
@@ -0,0 +1,73 @@
+@extends('layouts.app')
+
+@section('content')
+<div class="container">
+ <div class="row justify-content-center">
+ <div class="col-md-8">
+ <div class="card">
+ <div class="card-header">{{ __('Login') }}</div>
+
+ <div class="card-body">
+ <form method="POST" action="{{ route('login') }}">
+ @csrf
+
+ <div class="form-group row">
+ <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
+
+ <div class="col-md-6">
+ <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
+
+ @error('email')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
+
+ <div class="col-md-6">
+ <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
+
+ @error('password')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <div class="col-md-6 offset-md-4">
+ <div class="form-check">
+ <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
+
+ <label class="form-check-label" for="remember">
+ {{ __('Remember Me') }}
+ </label>
+ </div>
+ </div>
+ </div>
+
+ <div class="form-group row mb-0">
+ <div class="col-md-8 offset-md-4">
+ <button type="submit" class="btn btn-primary">
+ {{ __('Login') }}
+ </button>
+
+ @if (Route::has('password.request'))
+ <a class="btn btn-link" href="{{ route('password.request') }}">
+ {{ __('Forgot Your Password?') }}
+ </a>
+ @endif
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+@endsection
diff --git a/resources/views/auth/passwords/confirm.blade.php b/resources/views/auth/passwords/confirm.blade.php
new file mode 100644
index 0000000..ca78fc1
--- /dev/null
+++ b/resources/views/auth/passwords/confirm.blade.php
@@ -0,0 +1,49 @@
+@extends('layouts.app')
+
+@section('content')
+<div class="container">
+ <div class="row justify-content-center">
+ <div class="col-md-8">
+ <div class="card">
+ <div class="card-header">{{ __('Confirm Password') }}</div>
+
+ <div class="card-body">
+ {{ __('Please confirm your password before continuing.') }}
+
+ <form method="POST" action="{{ route('password.confirm') }}">
+ @csrf
+
+ <div class="form-group row">
+ <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
+
+ <div class="col-md-6">
+ <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
+
+ @error('password')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row mb-0">
+ <div class="col-md-8 offset-md-4">
+ <button type="submit" class="btn btn-primary">
+ {{ __('Confirm Password') }}
+ </button>
+
+ @if (Route::has('password.request'))
+ <a class="btn btn-link" href="{{ route('password.request') }}">
+ {{ __('Forgot Your Password?') }}
+ </a>
+ @endif
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+@endsection
diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php
new file mode 100644
index 0000000..1fea984
--- /dev/null
+++ b/resources/views/auth/passwords/email.blade.php
@@ -0,0 +1,47 @@
+@extends('layouts.app')
+
+@section('content')
+<div class="container">
+ <div class="row justify-content-center">
+ <div class="col-md-8">
+ <div class="card">
+ <div class="card-header">{{ __('Reset Password') }}</div>
+
+ <div class="card-body">
+ @if (session('status'))
+ <div class="alert alert-success" role="alert">
+ {{ session('status') }}
+ </div>
+ @endif
+
+ <form method="POST" action="{{ route('password.email') }}">
+ @csrf
+
+ <div class="form-group row">
+ <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
+
+ <div class="col-md-6">
+ <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
+
+ @error('email')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row mb-0">
+ <div class="col-md-6 offset-md-4">
+ <button type="submit" class="btn btn-primary">
+ {{ __('Send Password Reset Link') }}
+ </button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+@endsection
diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php
new file mode 100644
index 0000000..989931d
--- /dev/null
+++ b/resources/views/auth/passwords/reset.blade.php
@@ -0,0 +1,65 @@
+@extends('layouts.app')
+
+@section('content')
+<div class="container">
+ <div class="row justify-content-center">
+ <div class="col-md-8">
+ <div class="card">
+ <div class="card-header">{{ __('Reset Password') }}</div>
+
+ <div class="card-body">
+ <form method="POST" action="{{ route('password.update') }}">
+ @csrf
+
+ <input type="hidden" name="token" value="{{ $token }}">
+
+ <div class="form-group row">
+ <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
+
+ <div class="col-md-6">
+ <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>
+
+ @error('email')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
+
+ <div class="col-md-6">
+ <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
+
+ @error('password')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
+
+ <div class="col-md-6">
+ <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
+ </div>
+ </div>
+
+ <div class="form-group row mb-0">
+ <div class="col-md-6 offset-md-4">
+ <button type="submit" class="btn btn-primary">
+ {{ __('Reset Password') }}
+ </button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+@endsection
diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php
new file mode 100644
index 0000000..d236a48
--- /dev/null
+++ b/resources/views/auth/register.blade.php
@@ -0,0 +1,77 @@
+@extends('layouts.app')
+
+@section('content')
+<div class="container">
+ <div class="row justify-content-center">
+ <div class="col-md-8">
+ <div class="card">
+ <div class="card-header">{{ __('Register') }}</div>
+
+ <div class="card-body">
+ <form method="POST" action="{{ route('register') }}">
+ @csrf
+
+ <div class="form-group row">
+ <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
+
+ <div class="col-md-6">
+ <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>
+
+ @error('name')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
+
+ <div class="col-md-6">
+ <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">
+
+ @error('email')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
+
+ <div class="col-md-6">
+ <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
+
+ @error('password')
+ <span class="invalid-feedback" role="alert">
+ <strong>{{ $message }}</strong>
+ </span>
+ @enderror
+ </div>
+ </div>
+
+ <div class="form-group row">
+ <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
+
+ <div class="col-md-6">
+ <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
+ </div>
+ </div>
+
+ <div class="form-group row mb-0">
+ <div class="col-md-6 offset-md-4">
+ <button type="submit" class="btn btn-primary">
+ {{ __('Register') }}
+ </button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+@endsection
diff --git a/resources/views/auth/verify.blade.php b/resources/views/auth/verify.blade.php
new file mode 100644
index 0000000..9f8c1bc
--- /dev/null
+++ b/resources/views/auth/verify.blade.php
@@ -0,0 +1,28 @@
+@extends('layouts.app')
+
+@section('content')
+<div class="container">
+ <div class="row justify-content-center">
+ <div class="col-md-8">
+ <div class="card">
+ <div class="card-header">{{ __('Verify Your Email Address') }}</div>
+
+ <div class="card-body">
+ @if (session('resent'))
+ <div class="alert alert-success" role="alert">
+ {{ __('A fresh verification link has been sent to your email address.') }}
+ </div>
+ @endif
+
+ {{ __('Before proceeding, please check your email for a verification link.') }}
+ {{ __('If you did not receive the email') }},
+ <form class="d-inline" method="POST" action="{{ route('verification.resend') }}">
+ @csrf
+ <button type="submit" class="btn btn-link p-0 m-0 align-baseline">{{ __('click here to request another') }}</button>.
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+@endsection
diff --git a/resources/views/cinema-show.blade.php b/resources/views/cinema-show.blade.php
new file mode 100644
index 0000000..346a1f4
--- /dev/null
+++ b/resources/views/cinema-show.blade.php
@@ -0,0 +1,150 @@
+@extends('layouts.app')
+
+@section('styles')
+@include ('layouts.footer-style')
+
+.poster-detail {
+ width: 100%;
+ max-width: 350px;
+ border-radius: 4px;
+}
+
+.year {
+ color: #868e96;
+}
+
+.rating {
+ color: #868e96;
+ font-size: 0.9rem;
+}
+
+.movie-credits {
+ columns: 2;
+ column-gap: 20px;
+}
+
+@media (max-width: 768px) {
+ .movie-credits {
+ columns: 1;
+ }
+ .poster-detail {
+ max-width: 200px;
+ margin: 0 auto;
+ }
+}
+
+@endsection
+
+@section('content')
+<div class="container">
+ <div style="margin-top: 20px"></div>
+
+ @if ( ! is_null($movie) )
+ <div class="card">
+ <h1 class="card-header">
+ <a href="{{ route('cinema.index') }}" style="color:inherit;">← All Movies</a>
+ </h1>
+ <div class="card-body">
+ <div class="row">
+ <div class="col-md-3">
+ @if ( ! is_null($movie->poster_url) )
+ <img class="poster-detail" src="{{ $movie->poster_url }}" alt="{{ $movie->primary_title }} poster">
+ @else
+ <div class="no-poster">🎬</div>
+ @endif
+ </div>
+ <div class="col-md-9">
+ <h3>
+ {{ $movie->primary_title }}
+ @if ( ! is_null($movie->original_title) && $movie->original_title != $movie->primary_title )
+ <small class="text-muted">({{ $movie->original_title }})</small>
+ @endif
+ </h3>
+ <div class="mt-2">
+ @if ( ! is_null($movie->start_year) )
+ <span class="year">{{ $movie->start_year }}</span>
+ @endif
+ @if ( ! is_null($movie->runtime_minutes) )
+ @if ( ! is_null($movie->start_year) )
+ <span class="year"> · </span>
+ @endif
+ <span class="year">{{ $movie->runtime_minutes }} min</span>
+ @endif
+ @if ( ! is_null($movie->title_type) )
+ @if ( ! is_null($movie->start_year) || ! is_null($movie->runtime_minutes) )
+ <span class="year"> · </span>
+ @endif
+ <span class="badge badge-secondary">{{ $movie->title_type }}</span>
+ @endif
+ </div>
+ <div class="mt-1">
+ @if ( ! is_null($movie->average_rating) )
+ <span class="rating">⭐ {{ number_format($movie->average_rating, 1) }}</span>
+ @if ( ! is_null($movie->num_votes) )
+ <span class="year"> ({{ number_format($movie->num_votes) }} votes)</span>
+ @endif
+ @endif
+ </div>
+
+ @if ( ! empty($genres) )
+ <div class="mt-2">
+ @foreach( $genres as $genre )
+ <span class="badge badge-pill badge-primary">{{ $genre }}</span>
+ @endforeach
+ </div>
+ @endif
+
+ @if ( ! empty($movie->synopsis) )
+ <p class="card-text mt-3">
+ {{ strip_tags($movie->synopsis) }}
+ </p>
+ @endif
+
+ @if ( ! empty($directors) )
+ <div class="mt-3">
+ <h4>Directed by</h4>
+ <div class="movie-credits">
+ @foreach( $directors as $person )
+ <div>{{ $person->name }}</div>
+ @endforeach
+ </div>
+ </div>
+ @endif
+
+ @if ( ! empty($actors) )
+ <div class="mt-3">
+ <h4>Starring</h4>
+ <div class="movie-credits">
+ @foreach( $actors as $person )
+ <div>{{ $person->name }}</div>
+ @endforeach
+ </div>
+ </div>
+ @endif
+
+ @if ( ! is_null($movie->imdb_id) )
+ <div class="mt-3">
+ <a class="btn btn-outline-primary btn-sm" href="https://www.imdb.com/title/{{ $movie->imdb_id }}" target="_blank">View on IMDb</a>
+ </div>
+ @endif
+ </div>
+ </div>
+ </div>
+ </div>
+ @else
+ <div class="card">
+ <h1 class="card-header">Movie Not Found</h1>
+ <div class="card-body">
+ <p class="card-text">The requested movie could not be found.</p>
+ <a href="{{ route('cinema.index') }}" class="btn btn-outline-primary">Back to Movies</a>
+ </div>
+ </div>
+ @endif
+
+ <div style="margin-bottom: 20px"></div>
+</div>
+@endsection
+
+@section('footer')
+ @include ('layouts.footer')
+@endsection
diff --git a/resources/views/cinema.blade.php b/resources/views/cinema.blade.php
new file mode 100644
index 0000000..baa0802
--- /dev/null
+++ b/resources/views/cinema.blade.php
@@ -0,0 +1,174 @@
+@extends('layouts.app')
+
+@section('styles')
+@include ('layouts.footer-style')
+
+html {
+ height: inherit;
+}
+
+.movie-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20px;
+ margin-top: 20px;
+}
+
+.movie-card {
+ flex: 1 1 280px;
+ min-width: 250px;
+ max-width: 320px;
+}
+
+.movie-card .poster {
+ width: 100%;
+ aspect-ratio: 2 / 3;
+ object-fit: cover;
+ background-color: #333;
+ border-radius: 4px 4px 0 0;
+}
+
+.movie-card .year {
+ color: #868e96;
+ font-size: 0.85rem;
+}
+
+.movie-card .rating {
+ font-size: 0.9rem;
+ color: #868e96;
+}
+
+.movie-card .synopsis {
+ font-size: 0.875rem;
+ color: #6c757d;
+ display: -webkit-box;
+ -webkit-line-clamp: 4;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.movie-card h1 {
+ font-size: 1rem;
+ padding: 10px 12px 4px;
+ margin: 0;
+}
+
+.movie-card h1 a {
+ color: inherit;
+ text-decoration: none;
+}
+
+.movie-card h1 a:hover {
+ text-decoration: underline;
+}
+
+.movie-card .card-body {
+ padding: 0 12px 12px;
+}
+
+.no-poster {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ aspect-ratio: 2 / 3;
+ background-color: #495057;
+ color: #adb5bd;
+ font-size: 3rem;
+ border-radius: 4px 4px 0 0;
+}
+
+.permalink:hover {
+ text-decoration: none;
+}
+
+@endsection
+
+@section('content')
+<div class="container">
+ <div style="margin-top: 20px"></div>
+
+ <div class="card">
+ <h1 class="card-header">
+ @if ( isset($search_query) && $search_query != '' )
+ Movies matching <strong>"{{ $search_query }}"</strong>
+ @if ( "1" != $movies->currentPage() )
+ (Page {{ $movies->currentPage() }})
+ @endif
+ @else
+ Movies
+ @if ( "1" != $movies->currentPage() )
+ (Page {{ $movies->currentPage() }})
+ @endif
+ @endif
+ </h1>
+ <div class="card-body">
+ <p class="card-text">
+ @if ( isset($search_query) && $search_query != '' )
+ Found {{ $count }} movies matching <strong>"{{ $search_query }}"</strong>.
+ @else
+ Browse {{ number_format($count) }} movies from the database, ranked by rating and popularity.
+ @endif
+ </p>
+ <form class="form-inline" action="{{ route('cinema.search') }}" method="GET">
+ <input name="q" class="form-control mr-sm-2" type="text" placeholder="Search movies..." aria-label="Search" value="{{ isset($search_query) ? $search_query : '' }}">
+ <button class="btn btn-outline-primary my-2 my-sm-0" type="submit">Search</button>
+ </form>
+ </div>
+ </div>
+
+ @if ( 0 != $movies->count() )
+ <div class="movie-grid">
+ @foreach( $movies as $movie)
+ <div class="card movie-card">
+ <a href="{{ route('cinema.show', $movie->imdb_id) }}">
+ @if ( ! is_null($movie->poster_url) )
+ <img class="poster" src="{{ $movie->poster_url }}" alt="{{ $movie->primary_title }} poster" loading="lazy">
+ @else
+ <div class="no-poster">🎬</div>
+ @endif
+ </a>
+ <h1>
+ <a href="{{ route('cinema.show', $movie->imdb_id) }}">
+ {{ $movie->primary_title }}
+ </a>
+ </h1>
+ <div class="card-body">
+ <div>
+ @if ( ! is_null($movie->start_year) )
+ <span class="year">{{ $movie->start_year }}</span>
+ @endif
+ @if ( ! is_null($movie->runtime_minutes) )
+ @if ( ! is_null($movie->start_year) )
+ <span class="year"> · </span>
+ @endif
+ <span class="year">{{ $movie->runtime_minutes }} min</span>
+ @endif
+ </div>
+ <div class="mt-1">
+ @if ( ! is_null($movie->average_rating) )
+ <span class="rating">⭐ {{ number_format($movie->average_rating, 1) }}</span>
+ @if ( ! is_null($movie->num_votes) )
+ <span class="year"> ({{ number_format($movie->num_votes) }} votes)</span>
+ @endif
+ @endif
+ </div>
+ @if ( ! empty($movie->synopsis) )
+ <p class="card-text synopsis mt-2">
+ {{ strip_tags($movie->synopsis) }}
+ </p>
+ @endif
+ </div>
+ </div>
+ @endforeach
+ </div>
+
+ <div style="margin-bottom: 20px"></div>
+ {{ $movies->appends(Request::input())->links() }}
+ @endif
+</div>
+@endsection
+
+@section('footer')
+ @include ('layouts.footer')
+@endsection
diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php
new file mode 100644
index 0000000..05dfca9
--- /dev/null
+++ b/resources/views/home.blade.php
@@ -0,0 +1,23 @@
+@extends('layouts.app')
+
+@section('content')
+<div class="container">
+ <div class="row justify-content-center">
+ <div class="col-md-8">
+ <div class="card">
+ <div class="card-header">Dashboard</div>
+
+ <div class="card-body">
+ @if (session('status'))
+ <div class="alert alert-success" role="alert">
+ {{ session('status') }}
+ </div>
+ @endif
+
+ You are logged in!
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+@endsection
diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php
new file mode 100644
index 0000000..712cc36
--- /dev/null
+++ b/resources/views/index.blade.php
@@ -0,0 +1,49 @@
+@extends('layouts.app')
+
+@section('styles')
+@media ( max-width: 397px ) {
+ .btn-mobile-second {
+ margin-top: 1rem;
+ }
+ .btn-lg {
+ width: 100%;
+ }
+}
+html {
+ height: 100%;
+}
+.cover-heading {
+ margin-top: 4rem;
+}
+
+@endsection
+
+@section('content')
+
+@if ( "index" == Request::route()->getName() )
+<div class="text-center">
+ <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
+
+ <div role="main" class="inner cover">
+ <h1 class="cover-heading">The Most Interesting Articles On Wikipedia</h1>
+<br>
+ <p class="lead">
+ Best of Wikipedia, filtered, tagged and discussed. <br>For the curious reader.
+ </p>
+<br>
+ <p class="lead">
+ <a href="{{ route('popular') }}" class="btn btn-lg btn-outline-primary">Most Popular</a>
+ <a href="{{ route('popular_topics') }}" class="btn btn-lg btn-outline-primary btn-mobile-second">Popular Topics</a>
+ </p>
+ <p class="lead mt-50">
+ <a href="{{ route('about') }}">What, why and how❔</a>
+ <br>
+ <br>
+ Follow on <a title="Follow on Mastodon {{ env('MASTODON_HANDLE') }}" href="{{ env('MASTODON_URL') }}" target="_blank">{!! file_get_contents(public_path() . "/img/mastodon.svg") !!} Mastodon</a>
+ </p>
+ </div>
+
+</div>
+</div>
+ @endif
+@endsection
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php
new file mode 100644
index 0000000..35c57b4
--- /dev/null
+++ b/resources/views/layouts/app.blade.php
@@ -0,0 +1,178 @@
+<!doctype html>
+<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <!-- CSRF Token -->
+ <meta name="csrf-token" content="{{ csrf_token() }}">
+
+ <link rel="me" href="https://mstdn.social/@MostDiscussed">
+ <link rel="me" href="https://mastodon.social/@MostDiscussed">
+
+ <title>{{ config('app.name', 'Laravel') }}
+ @if( str_starts_with(Request::route()->getName(), 'cinema') )
+ - Movies
+ @elseif( ("index" != Request::route()->getName()) && ("show" != Request::route()->getName()) )
+ - {{ ucwords(Request::route()->getName()) }} Articles
+ @elseif ( "show" == Request::route()->getName() )
+ - {{ ucwords( $page_title) }}
+ @endif
+ </title>
+
+ <!-- Scripts -->
+ <script src="{{ asset('js/app.js') }}" defer></script>
+
+ <!-- Fonts -->
+<style>
+ /* cyrillic-ext */
+ @font-face {
+ font-family: 'Nunito';
+ font-style: normal;
+ font-weight: 400;
+ src: url(/fonts/Nunito.normal.400.U+0460-052F.U+1C80-1C88.U+20B4.U+2DE0-2DFF.U+A640-A69F.U+FE2E-FE2F.woff2) format('woff2');
+ unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
+ }
+ /* cyrillic */
+ @font-face {
+ font-family: 'Nunito';
+ font-style: normal;
+ font-weight: 400;
+ src: url(/fonts/Nunito.normal.400.U+0301.U+0400-045F.U+0490-0491.U+04B0-04B1.U+2116.woff2) format('woff2');
+ unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
+ }
+ /* vietnamese */
+ @font-face {
+ font-family: 'Nunito';
+ font-style: normal;
+ font-weight: 400;
+ src: url(/fonts/Nunito.normal.400.U+0102-0103.U+0110-0111.U+0128-0129.U+0168-0169.U+01A0-01A1.U+01AF-01B0.U+1EA0-1EF9.U+20AB.woff2) format('woff2');
+ unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
+ }
+ /* latin-ext */
+ @font-face {
+ font-family: 'Nunito';
+ font-style: normal;
+ font-weight: 400;
+ src: url(/fonts/Nunito.normal.400.U+0100-024F.U+0259.U+1E00-1EFF.U+2020.U+20A0-20AB.U+20AD-20CF.U+2113.U+2C60-2C7F.U+A720-A7FF.woff2) format('woff2');
+ unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
+ }
+ /* latin */
+ @font-face {
+ font-family: 'Nunito';
+ font-style: normal;
+ font-weight: 400;
+ src: url(/fonts/Nunito.normal.400.U+0000-00FF.U+0131.U+0152-0153.U+02BB-02BC.U+02C6.U+02DA.U+02DC.U+2000-206F.U+2074.U+20AC.U+2122.U+2191.U+2193.U+2212.U+2215.U+FEFF.U+FFFD.woff2) format('woff2');
+ unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
+ }
+</style>
+
+ <!-- Styles -->
+ <link href="{{ asset('css/app.css') }}" rel="stylesheet">
+
+ <style>
+ @yield('styles')
+ </style>
+ @if ( "new" == Request::route()->getName() || "popular" == Request::route()->getName() )
+ {!! Rumenx\Feed\Feed::link( url('feed/' . Request::route()->getName()), 'atom', 'RSS-Feed for ' . Request::route()->getName() . ' Articles'); !!}
+ @endif
+
+@if ( "" != env( "MATOMO_ID" ) )
+<script type="text/javascript">
+ var _paq = window._paq || [];
+ /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
+ _paq.push(['trackPageView']);
+ _paq.push(['enableLinkTracking']);
+ (function() {
+ var u="{{ env("MATOMO_URL") }}";
+ _paq.push(['setTrackerUrl', u+'/jsx/']);
+ _paq.push(['setSiteId', '{{env( "MATOMO_ID" )}}']);
+ var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
+ g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'/jsx/'; s.parentNode.insertBefore(g,s);
+ })();
+</script>
+<noscript><p><img src="{{ env("MATOMO_URL") }}/jsx/?idsite={{ env("MATOMO_ID") }}&amp;rec=1" style="border:0;" alt="" /></p></noscript>
+@endif
+
+</head>
+<body class="d-flex flex-column h-100">
+ <div id="app">
+ <nav class="navbar navbar-expand-md navbar-dark shadow-sm">
+ <div class="container">
+ <a class="navbar-brand" href="{{ url('/') }}">
+ {{ config('app.name', 'Laravel') }}
+ </a>
+ <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
+ <span class="navbar-toggler-icon"></span>
+ </button>
+
+ <div class="collapse navbar-collapse" id="navbarSupportedContent">
+ <!-- Left Side Of Navbar -->
+ <ul class="navbar-nav mr-auto">
+
+ </ul>
+
+ <!-- Right Side Of Navbar -->
+ <ul class="navbar-nav ml-auto">
+ <!-- Authentication Links -->
+ @guest
+ @if (Route::has('login'))
+ <li class="nav-item">
+ <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
+ </li>
+ @endif
+ @if (Route::has('register'))
+ <li class="nav-item">
+ <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
+ </li>
+ @endif
+ <li class="nav-item">
+ <a class="nav-link" href="{{ route('new') }}">{{ __('New') }}</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="{{ route('popular') }}">{{ __('Popular') }}</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="{{ route('popular_topics') }}">{{ __('Topics') }}</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="{{ route('random') }}">{{ __('Random') }}</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="{{ route('cinema.index') }}">{{ __('Cinema') }}</a>
+ </li>
+ @else
+ <li class="nav-item dropdown">
+ <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
+ {{ Auth::user()->name }} <span class="caret"></span>
+ </a>
+
+ <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
+ <a class="dropdown-item" href="{{ route('logout') }}"
+ onclick="event.preventDefault();
+ document.getElementById('logout-form').submit();">
+ {{ __('Logout') }}
+ </a>
+
+ <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
+ @csrf
+ </form>
+ </div>
+ </li>
+ @endguest
+ <form class="form-inline mt-2 mt-md-0 navbar-searchform" action="{{ route('search') }}">
+ <input name="q" class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search" required>
+ <button class="btn btn-outline-primary my-2 my-sm-0" type="submit">Search</button>
+ </form>
+ </ul>
+ </div>
+ </div>
+ </nav>
+
+ <main class="">
+ @yield('content')
+ </main>
+ @yield('footer')
+ </div>
+</body>
+</html>
diff --git a/resources/views/layouts/footer-style.blade.php b/resources/views/layouts/footer-style.blade.php
new file mode 100644
index 0000000..e1f715e
--- /dev/null
+++ b/resources/views/layouts/footer-style.blade.php
@@ -0,0 +1,14 @@
+html {
+ position: relative;
+ min-height: 100%;
+}
+body {
+ margin-bottom: 120px;
+}
+.footer {
+ position: absolute;
+ bottom: 50;
+ width: 100%;
+ height: 70px;
+}
+
diff --git a/resources/views/layouts/footer.blade.php b/resources/views/layouts/footer.blade.php
new file mode 100644
index 0000000..5a8c6e8
--- /dev/null
+++ b/resources/views/layouts/footer.blade.php
@@ -0,0 +1,18 @@
+<div class="container mt-35">
+ <hr>
+</div>
+
+<div class="mt-20"></div>
+
+<footer class="footer">
+ <div class="container">
+ <h3 class="text-white">
+ Helpful Links
+ </h3>
+ <strong>
+ <a href="{{ route('about') }}">About {{ env('APP_NAME') }}</a>
+ <br>
+ <a target="_blank" title="Follow on Mastodon {{ env('MASTODON_HANDLE') }}" href="{{ env('MASTODON_URL') }}">Follow on {!! file_get_contents(public_path() . "/img/mastodon.svg") !!} Mastodon</a>
+ </strong>
+ </div>
+</footer>
diff --git a/resources/views/list.blade.php b/resources/views/list.blade.php
new file mode 100644
index 0000000..5878aa9
--- /dev/null
+++ b/resources/views/list.blade.php
@@ -0,0 +1,177 @@
+@extends('layouts.app')
+
+@section('styles')
+
+@include ('layouts.footer-style')
+
+@if ( 0 != $count )
+ html {
+ height: inherit;
+ }
+ .hn {
+ display: inline-block;
+ font-size: inherit;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -.125em;
+ fill: #ff6600;
+ }
+
+ .rss-link > svg {
+ display: inline-block;
+ font-size: inherit;
+ height: 1em;
+ overflow: visible;
+ vertical-align: -.125em;
+ fill: #f59436;
+ }
+@endif
+
+.permalink:hover {
+ text-decoration: none;
+}
+
+@endsection
+
+@section('content')
+ <div class="container">
+
+ <div style="margin-top: 20px"></div>
+ <div class="card">
+ @if ( "search" == Request::route()->getName() )
+ <h1 class="card-header">
+ Search for <strong>"{{ Request::input("q") }}"</strong>
+ @if ( "1" != $articles->currentPage() )
+ (Page {{ $articles->currentPage() }})
+ @endif
+ </h1>
+ <div class="card-body">
+ <p class="card-text">
+ You searched for <strong>"{{ Request::input("q") }}"</strong>. We found {{ $count }} matches.
+ </p>
+ @include("search")
+ </div>
+ @elseif ( "topic" == Request::route()->getName() )
+ <h1 class="card-header">
+ Topic: <strong>{{ Request::route()->parameters()["topic"] }}</strong>
+ @if ( "1" != $articles->currentPage() )
+ (Page {{ $articles->currentPage() }})
+ @endif
+ </h1>
+ <div class="card-body">
+ <p class="card-text">
+ You are looking at all articles with the topic <strong>"{{ Request::route()->parameters()["topic"] }}"</strong>. We found {{ $count }} matches.
+ <br>
+ <br>
+ <strong>Hint:</strong>
+ <em>To view all topics, <a href="{{ route('topic_index') }}" title="all topics">click here</a>. Too see the most popular topics, <a href="{{ route('popular_topics') }}" title="popular topics">click here instead</a>.</em>
+ </p>
+ </div>
+ @elseif ( "random" == Request::route()->getName() )
+ <h1 class="card-header">
+ {{ ucwords(Request::route()->getName()) }} Articles
+ @if ( "1" != $articles->currentPage() )
+ (Page {{ $articles->currentPage() }})
+ @endif
+ </h1>
+ <div class="card-body">
+ <p class="card-text">
+ Have a deep view into what people are curious about.
+ </p>
+ </div>
+ @elseif ( "show" == Request::route()->getName() )
+ <!-- single article. show nothing -->
+ @else
+ <h1 class="card-header">
+ {{ ucwords(Request::route()->getName()) }} Articles
+ @if ( "1" != $articles->currentPage() )
+ (Page {{ $articles->currentPage() }})
+ @endif
+ <div class="float-right">
+ <a class="rss-link" href="{{ route('feed_' . Request::route()->getName()) }}" title="RSS-Feed">
+ {!! file_get_contents(public_path() . "/img/rss-square.svg") !!}
+ </a>
+ </div>
+ </h1>
+ @if ( "popular" == Request::route()->getName() )
+ <div class="card-body">
+ <p class="card-text">
+ <strong>Hint:</strong>
+ <em>You are looking at the most popular articles. If you are interested in </em><strong>popular topics</strong><em> instead, <a href="{{ route('popular_topics') }}" title="popular topics">click here</a>.</em>
+ </p>
+ </div>
+ @elseif ( "new" == Request::route()->getName() )
+ <div class="card-body">
+ <p class="card-text">
+ To stay up to date you can also follow on <a title="Follow on Mastodon {{ env('MASTODON_HANDLE') }}" href="{{ env('MASTODON_URL') }}" target="_blank">{!! file_get_contents(public_path() . "/img/mastodon.svg") !!} Mastodon</a>.
+ </p>
+ </div>
+ @endif
+
+ @endif
+ </div>
+ <div style="margin-bottom: 20px"></div>
+
+ @foreach( $articles->all() as $article)
+ <div class="card">
+ <h1 class="card-header">
+ <a style="color:inherit;" href="{{ $article->url }}" title="{{ $article->title }}">
+ 🔗 {{ $article->title }}
+ </a>
+@if ( "show" != Request::route()->getName() )
+ <div class="float-right">
+ <a class="permalink" href="{{ route('show', $article->id) }}" title="Permalink">🛈</a>
+ </div>
+@endif
+ </h1>
+ <div class="card-body">
+ @if ( ! is_null($article->getCategories()) )
+ @foreach ( $article->getCategories()->get() as $cat )
+ <a class="badge badge-pill badge-primary" href="/topic/{{ $cat->name }}">
+ 🔗 {{ $cat->name }}
+ </a>
+ @endforeach
+ @endif
+ <p class="card-text">
+ {!! $article->excerpt_html !!}
+ </p>
+
+
+ @if ( 0 != $article->comments )
+ <div class="row">
+ <div class="col">
+ <h3 class="card-subtitle">Discussed on</h3>
+ <ul class="list-unstyled">
+ @foreach ( $article->where('id', $article->article_id)->first()->getDiscussions()->orderBy('posted_on', 'desc')->get() as $discussion )
+ @if ( 0 != $discussion->comments )
+ <li>
+ <a class="card-links" href="{{ $discussion->source_url }}">
+ @if ( "HN" == $discussion->source )
+ {!! file_get_contents(public_path() . "/img/y-combinator.svg") !!}
+ @endif
+ "{{ $discussion->title }}"
+ </a>
+ | {{ \App\Libraries\Helper::formatTimestamp($discussion->posted_on) }} |
+ <span class="badge badge-pill badge-secondary">{{ $discussion->upvotes }} Upvotes</span>
+ <span class="badge badge-pill badge-secondary">{{ $discussion->comments }} Comments </span>
+ </li>
+ @endif
+ @endforeach
+ </ul>
+ </div>
+ </div>
+ @endif
+ </div>
+ </div>
+
+ <div style="margin-bottom: 20px"></div>
+ @endforeach
+
+ {{ $articles->appends(Request::input())->links() }}
+
+ </div>
+@endsection
+
+@section ('footer')
+ @include ('layouts.footer')
+@endsection
diff --git a/resources/views/search.blade.php b/resources/views/search.blade.php
new file mode 100644
index 0000000..921a3c2
--- /dev/null
+++ b/resources/views/search.blade.php
@@ -0,0 +1,19 @@
+ <form>
+ <div class="form-row align-items-center">
+ <div class="col-auto">
+ <label class="sr-only" for="inlineFormInput">Search</label>
+ <input type="text" class="form-control mb-2" id="q" name="q" placeholder="Search..." required>
+ </div>
+ <div class="col-auto">
+ <div class="form-check mb-2">
+ <input class="form-check-input" type="checkbox" id="onlypopular" name="onlypopular">
+ <label class="form-check-label" for="onlypopular">
+ Click to filter for popularity
+ </label>
+ </div>
+ </div>
+ <div class="col-auto">
+ <button type="submit" class="btn btn-primary mb-2">Search</button>
+ </div>
+ </div>
+ </form>
diff --git a/resources/views/topicindex.blade.php b/resources/views/topicindex.blade.php
new file mode 100644
index 0000000..67b0de4
--- /dev/null
+++ b/resources/views/topicindex.blade.php
@@ -0,0 +1,50 @@
+@extends('layouts.app')
+
+@section('styles')
+@include ('layouts.footer-style')
+html {
+ height: inherit;
+}
+@endsection
+
+@section ('content')
+
+<div class="text-center container">
+
+<div class="container row text-white text-lg">
+ <ul class="list-inline">
+ @foreach ($letters as $letter)
+ <li class="list-inline-item">
+ <a href="#{{$letter->name}}" class="text-white">{{$letter->name}}</a>
+ </li>
+ @endforeach
+ </ul>
+</div>
+
+@php ($curLetter = "")
+@foreach ($topics->get() as $topic)
+ @if ( "" != $topic->name )
+ @php ( $firstLetter = strtoupper(substr($topic->name, 0, 1)) )
+ @if ( $curLetter != $firstLetter )
+ <div class="container row">
+ <h2 id="{{$firstLetter}}">
+ <a class="text-white" href="#{{$firstLetter}}">
+ {{ $firstLetter }}
+ </a>
+ </h2>
+ </div>
+ <hr>
+
+ @php ($curLetter = $firstLetter)
+
+ @endif
+ <a href="{{ route('topic', $topic->name) }}" class="btn btn-lg btn-outline-primary">{{ ucwords($topic->name) }}</a>
+ @endif
+@endforeach
+
+</div>
+@endsection
+
+@section ('footer')
+ @include ('layouts.footer')
+@endsection
diff --git a/resources/views/topicpopular.blade.php b/resources/views/topicpopular.blade.php
new file mode 100644
index 0000000..2259398
--- /dev/null
+++ b/resources/views/topicpopular.blade.php
@@ -0,0 +1,48 @@
+@extends ('layouts.app')
+
+@section ('styles')
+@include ('layouts.footer-style')
+html {
+ height: inherit;
+}
+@endsection
+
+@section ('content')
+
+<div class="container">
+
+ <div style="margin-top: 20px"></div>
+ <div class="card">
+ <h1 class="card-header">
+ Popular Topics
+ </h1>
+ <div class="card-body">
+ <p class="card-text">
+ <strong>Hint:</strong> <em>You are looking at popular topics. If you are interested in the most </em><strong>popular articles</strong><em> instead, <a href="{{ route('popular') }}" alt="popular articles">click here instead</a>.</em>
+ </p>
+ <p class="card-text">
+ <strong>Hint:</strong>
+ <em>
+ For a list of all topics please <a href="{{ route('topic_index') }}" alt="all topics">click here</a>.
+ </em>
+ </p>
+ </div>
+ </div>
+ <div style="margin-bottom: 20px"></div>
+
+ <div class="text-center card">
+ <div class="card-body">
+ @foreach ($topics as $topic)
+ @if ( "" != $topic->name )
+ <a href="{{ route('topic', $topic->name) }}" class="btn btn-lg btn-primary mx-1 my-1">{{ ucwords($topic->name) }} ({{ $topic->count }} Articles)</a>
+ @endif
+ @endforeach
+ </div>
+ </div>
+
+</div>
+@endsection
+
+@section ('footer')
+ @include ('layouts.footer')
+@endsection
diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php
new file mode 100644
index 0000000..3fb48cc
--- /dev/null
+++ b/resources/views/welcome.blade.php
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <title>Laravel</title>
+
+ <!-- Fonts -->
+ <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
+
+ <!-- Styles -->
+ <style>
+ html, body {
+ background-color: #fff;
+ color: #636b6f;
+ font-family: 'Nunito', sans-serif;
+ font-weight: 200;
+ height: 100vh;
+ margin: 0;
+ }
+
+ .full-height {
+ height: 100vh;
+ }
+
+ .flex-center {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ }
+
+ .position-ref {
+ position: relative;
+ }
+
+ .top-right {
+ position: absolute;
+ right: 10px;
+ top: 18px;
+ }
+
+ .content {
+ text-align: center;
+ }
+
+ .title {
+ font-size: 84px;
+ }
+
+ .links > a {
+ color: #636b6f;
+ padding: 0 25px;
+ font-size: 13px;
+ font-weight: 600;
+ letter-spacing: .1rem;
+ text-decoration: none;
+ text-transform: uppercase;
+ }
+
+ .m-b-md {
+ margin-bottom: 30px;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="flex-center position-ref full-height">
+ @if (Route::has('login'))
+ <div class="top-right links">
+ @auth
+ <a href="{{ url('/home') }}">Home</a>
+ @else
+ <a href="{{ route('login') }}">Login</a>
+
+ @if (Route::has('register'))
+ <a href="{{ route('register') }}">Register</a>
+ @endif
+ @endauth
+ </div>
+ @endif
+
+ <div class="content">
+ <div class="title m-b-md">
+ Laravel
+ </div>
+
+ <div class="links">
+ <a href="https://laravel.com/docs">Docs</a>
+ <a href="https://laracasts.com">Laracasts</a>
+ <a href="https://laravel-news.com">News</a>
+ <a href="https://blog.laravel.com">Blog</a>
+ <a href="https://nova.laravel.com">Nova</a>
+ <a href="https://forge.laravel.com">Forge</a>
+ <a href="https://vapor.laravel.com">Vapor</a>
+ <a href="https://github.com/laravel/laravel">GitHub</a>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>