$message->subject($subject . $validatedData['subject']);
});
}
+
+ // Subscribe to newsletter via MailChimp API
+ public function newsletter(Request $request)
+ {
+ $validator = Validator::make(
+ $request->all(),
+ [
+ 'email' => 'required|email',
+ ],
+ [
+ 'email.required' => __('Champ obligatoire'),
+ 'email.email' => __('Adresse e-mail invalide'),
+ ]
+ );
+
+ $validator->validate();
+
+ // TODO: implement MailChimp API (https://developer.mailchimp.com/documentation/mailchimp/guides/manage-subscribers-with-the-mailchimp-api/)
+ //$validatedData = $validator->validated();
+ //dd($validatedData);
+
+ return [];
+ }
}
}
$this->data['title'] = $newsItem->title;
- $this->data['news'] = $newsItem->getPageData();
- $this->data['image'] = $this->data['news']->getImageURL('image', 'thumb');
+ $this->data['image'] = $newsItem->getFirstMediaUrl($newsItem->image, 'thumb');
+ $this->data['news'] = $newsItem;
return view('pages.news-detail', $this->data);
}
$this->addMediaConversion('thumb')
->crop('crop-center', 348, 232);
}
+
+ // Display compact date range in localised human readable format
+ // Ref: https://codereview.stackexchange.com/a/78303
+ // Alternative: https://github.com/flack/ranger
+ public function formatDateRange($start, $end) {
+
+ if ($start->format('Y-m-d') === $end->format('Y-m-d')) {
+ # Same day
+ return $start->isoFormat('D MMMM Y');
+
+ } elseif ($start->format('Y-m') === $end->format('Y-m')) {
+ # Same calendar month
+ return $start->isoFormat('D') . $end->isoFormat('–D MMMM YYYY');
+
+ } elseif ($start->format('Y') === $end->format('Y')) {
+ # Same calendar year
+ return $start->isoFormat('D MMMM') . $end->isoFormat(' – D MMMM Y');
+
+ } else {
+ # General case (spans calendar years)
+ return $start->isoFormat('D MMMM Y') . $end->isoFormat(' – D MMMM Y');
+ }
+ }
}
continue;
}
+ // Todo: see if we should handle events differently? Should events have a different ID + URL and maybe a different controller action in case we need a different layout?
+
$item = new Item();
$item->setTitle($newsItem->title);
$item->setHref($newsItem->slug); // Todo: consider having a configurable / translatable prefix for news URLs
data: $(this).serialize(),
}).done(function (response) {
$(form).find('.error').removeClass('error');
- $(form).closest('#contact-form').html('<p class="center text-2xl text-center p-8" >' + $(form).data('confirmation') + '</p>');
+ // Todo: make this more customisable from the form
+ $(form).html('<p class="center text-2xl text-center p-8" >' + $(form).data('confirmation') + '</p>');
}).fail(function (response) {
button.text(button.data('text')).prop('disabled', false);
$(form).find('.error').removeClass('error');
-#contact-form
- .form
-
- .fields
- grid-column-gap: 30px
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
-
- .errormessage
- color theme('colors.red')
- font-weight: 300
- position: absolute
- right: 0
- top: 15px
- text-align: right
-
- input, textarea
- border-radius 3px
- color: theme('colors.grey.dark')
- padding 12px 10px
- border 1px solid #fff
- display: block
- width: 100%
-
- &:focus
- border-color: theme('colors.grey.250')
-
- &.error
- border-color: theme('colors.red')
-
- label
- font-family: theme('fontFamily.body')
- position: relative
- padding-top: 15px
- display: block
-
- &:not(.half)
- grid-column 1 / -1
-
- .textarea
- height 144px
- display: block
-
- &-endmessage
- font-size: 14px
- margin-bottom: 20px;
-
- .btn-custom
- min-width 14rem
- padding 1.125rem 3.375rem
+.ajax-form
+
+ .fields
+ grid-column-gap: 30px
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+
+ .errormessage
+ color theme('colors.red')
+ font-weight: 300
+ position: absolute
+ right: 0
+ top: 15px
+ text-align: right
+
+ input, textarea
+ border-radius 3px
+ color: theme('colors.grey.dark')
+ padding 12px 10px
+ border 1px solid #fff
+ display: block
+ width: 100%
+
+ &:focus
+ border-color: theme('colors.grey.250')
+
+ &.error
+ border-color: theme('colors.red')
+
+ label
+ font-family: theme('fontFamily.body')
+ position: relative
+ padding-top: 15px
+ display: block
+
+ &:not(.half)
+ grid-column 1 / -1
+
+ .textarea
+ height 144px
+ display: block
+
+ &-endmessage
+ font-size: 14px
+ margin-bottom: 20px;
+
+ .btn-custom
+ min-width 14rem
+ padding 1.125rem 3.375rem
-.news
- // 3 column layout with image / text / sidebar
+//=== News Index Page
+// 2 column layout with articles / sidebar
+// Internal grid for each article
+.news-index
+ &-layout
+ display: grid
+ constrain(grid-gap, 2.5vw)
+ grid-template: "articles sidebar" auto / 3fr 1fr
+ grid-template-rows: max-content
+ grid-template-columns: auto
+
+ +below(768px)
+ grid-template-areas: "articles" "sidebar"
+
+ &-articles
+ grid-area: articles
+
+ // Internal grid for each article
+ &-article
+ display: grid
+ constrain(grid-gap, 2.5vw)
+ grid-template: "image text" auto / 1fr 2.25fr
+
+ &:not(:last-child)
+ constrain(margin-bottom, 2.5vw)
+
+ +below(1000px)
+ grid-template: "image" "text" auto / 1fr
+ &:not(:last-child)
+ margin-bottom: 5vw
+
+ &-image
+ grid-area: image
+
+ &-text
+ grid-area: text
+
+ &-sidebar
+ grid-area: sidebar
+
+
+//=== Individual News Post
+// 3 column layout with image / text / sidebar
+.news-post
&-layout
display: grid
constrain(grid-gap, 2.5vw)
&-sidebar
grid-area: sidebar
- min-width: 260px
+ min-width: 320px
<content>
<text-block :title="$news->title" title-tag="h1" />
- <div class="news-layout">
+ <div class="news-post-layout">
@if ($image)
{{-- Todo: use larger image + srcset here --}}
- <img src="{{ $image }}" alt="{{ $title }}" class="news-image">
+ <img src="{{ $image }}" alt="{{ $title }}" class="news-post-image">
@endif
- <div class="news-body">
- <p>{{ date('d/m/y', strtotime($news->date['date'])) }}</p>
+ <div class="news-post-body">
+ <time datetime="{{ $news->date->toDateTimeLocalString() }}" class="block mb-2 text-sm">
+ {{ $news->date->format('d/m/y') }}
+ </time>
@markdown($news->content)
</div>
- <div class="news-sidebar bg-grey-100 p-1v">
- (Newsletter Form)
+ <div class="news-post-sidebar">
+ <div class="bg-grey-100 p-1v">
+ @include('partials.newsletter-form')
+ </div>
</div>
</div>
<content>
{{-- Todo: use grid for main (generic?) sidebar layout and utilise minmax for content? --}}
- <div class="news-index-layout flex">
+ <div class="news-index-layout">
- <div class="news-items">
+ <div class="news-index-articles">
@foreach ($news as $newsItem)
@php
$newsURL = $nav->getHrefByID("news/{$newsItem->id}");
@endphp
- {{-- Todo: use smaller grid for each article: 1fr image, 2fr content with a minmax on image to auto wrap --}}
- <article class="flex">
+ <article class="news-index-article">
- <a href="{{ $newsURL }}" class="news-item-image">
+ <a href="{{ $newsURL }}" class="news-index-article-image">
{{--Todo: handle missing images + get correct image size--}}
- <img class="mb-1v mr-1v" src="{{ $newsItem->getFirstMediaUrl($newsItem->image, 'thumb') }}" alt="{{ $newsItem->title }}">
+ <img src="{{ $newsItem->getFirstMediaUrl($newsItem->image, 'thumb') }}" alt="{{ $newsItem->title }}">
</a>
- <div class="news-item-text">
- <h4 class="font-display">{{ $newsItem->title }}</h4>
+ <div class="news-index-article-text">
+ <time datetime="{{ $newsItem->date->toDateTimeLocalString() }}" class="block mb-2 text-sm">
+ {{ $newsItem->date->format('d/m/y') }}
+ </time>
+ <h4 class="text-2xl">{{ $newsItem->title }}</h4>
<p>{{ $newsItem['chapo'] }}</p>
<p><a href="{{ $newsURL }}">{{ __('En savoir plus') }}</a></p>
@endforeach
</div>
- <div class="news-sidebar">
+ <div class="news-index-sidebar">
<div class="bg-grey-100 p-1v mb-1v">
- Events
+ <h3 class="text-2xl">{{ __('Évènements') }}</h3>
+ @foreach($events as $event)
+ @php
+ $eventURL = $nav->getHrefByID("news/{$event->id}"); // Todo: possibly events will have different IDs
+ @endphp
+
+ <div class="event @if(!$loop->last) mb-8 @endif">
+ <a href="{{ $eventURL }}">
+ <img src="{{ $event->getFirstMediaUrl($event->image, 'thumb') }}" alt="{{ $event->title }}" style="max-width:252px" class="mb-3">
+ </a>
+ <h4 class="font-medium mb-1">{{ $event->title }}</h4>
+ <p>{{ $event->formatDateRange($event->event_start, $event->event_end) }}, {{ $event->event_place }}</p>
+ <p class="-mt-4"><a href="{{ $eventURL }}">{{ __('En savoir plus') }}</a></p>
+ </div>
+ @endforeach
</div>
<div class="bg-grey-100 p-1v">
- Newsletter subscribe
+ @include('partials.newsletter-form')
</div>
</div>
@endpush
<div id="contact-form">
- <div class="form flex flex-col">
+ <div class="ajax-form flex flex-col">
@if($page->get('form_intro'))
<p class="form-info text-navy">{{$page->get('form_intro')}}</p>
@endif
--- /dev/null
+@push('scripts')
+ <script src="{{ mix('/js/mailform.js') }}"></script>
+@endpush
+
+<h3 class="text-2xl">
+ {{ __('Inscription Newsletter') }}
+</h3>
+
+<form action="/ajax/newsletter" method="post" class="ajax-form mailform text-navy" data-confirmation="{{ __('Merci, vous avez été inscrit avec succès') }}" novalidate>
+ <label for="newsletter_email" class="form-input">{{ __('Email') }}
+ <input type="email" name="email" id="newsletter_email" class="py-3 mt-3" required>
+ </label>
+ <button type="submit" class="mt-4 btn w-full sm:w-auto sm:block sm:ml-auto xs:w-full" data-sending="{{ __('Attendez') }}">{{ __("S'inscrire") }}</button>
+</form>