Add podcast listing page
This commit is contained in:
parent
203056d54a
commit
fc1beaf3fb
10 changed files with 414 additions and 2 deletions
|
@ -48,6 +48,7 @@ module:
|
||||||
metatag_twitter_cards: 0
|
metatag_twitter_cards: 0
|
||||||
node: 0
|
node: 0
|
||||||
opd_daily_emails: 0
|
opd_daily_emails: 0
|
||||||
|
opd_podcast: 0
|
||||||
options: 0
|
options: 0
|
||||||
page_cache: 0
|
page_cache: 0
|
||||||
path: 0
|
path: 0
|
||||||
|
|
|
@ -14,4 +14,4 @@ description: null
|
||||||
help: null
|
help: null
|
||||||
new_revision: true
|
new_revision: true
|
||||||
preview_mode: 1
|
preview_mode: 1
|
||||||
display_submitted: false
|
display_submitted: true
|
||||||
|
|
204
config/sync/views.view.podcast_episodes.yml
Normal file
204
config/sync/views.view.podcast_episodes.yml
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
uuid: 18036b67-1a46-4b88-a11c-64253e3e2ada
|
||||||
|
langcode: en
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
config:
|
||||||
|
- core.entity_view_mode.node.teaser
|
||||||
|
- node.type.podcast_episode
|
||||||
|
module:
|
||||||
|
- node
|
||||||
|
- user
|
||||||
|
id: podcast_episodes
|
||||||
|
label: 'Podcast episodes'
|
||||||
|
module: views
|
||||||
|
description: ''
|
||||||
|
tag: ''
|
||||||
|
base_table: node_field_data
|
||||||
|
base_field: nid
|
||||||
|
display:
|
||||||
|
default:
|
||||||
|
id: default
|
||||||
|
display_title: Default
|
||||||
|
display_plugin: default
|
||||||
|
position: 0
|
||||||
|
display_options:
|
||||||
|
title: 'The Beyond Blocks Podcast'
|
||||||
|
fields:
|
||||||
|
title:
|
||||||
|
id: title
|
||||||
|
table: node_field_data
|
||||||
|
field: title
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
entity_type: node
|
||||||
|
entity_field: title
|
||||||
|
plugin_id: field
|
||||||
|
label: ''
|
||||||
|
exclude: false
|
||||||
|
alter:
|
||||||
|
alter_text: false
|
||||||
|
make_link: false
|
||||||
|
absolute: false
|
||||||
|
word_boundary: false
|
||||||
|
ellipsis: false
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: true
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
|
element_default_classes: true
|
||||||
|
empty: ''
|
||||||
|
hide_empty: false
|
||||||
|
empty_zero: false
|
||||||
|
hide_alter_empty: true
|
||||||
|
click_sort_column: value
|
||||||
|
type: string
|
||||||
|
settings:
|
||||||
|
link_to_entity: true
|
||||||
|
group_column: value
|
||||||
|
group_columns: { }
|
||||||
|
group_rows: true
|
||||||
|
delta_limit: 0
|
||||||
|
delta_offset: 0
|
||||||
|
delta_reversed: false
|
||||||
|
delta_first_last: false
|
||||||
|
multi_type: separator
|
||||||
|
separator: ', '
|
||||||
|
field_api_classes: false
|
||||||
|
pager:
|
||||||
|
type: mini
|
||||||
|
options:
|
||||||
|
offset: 0
|
||||||
|
pagination_heading_level: h4
|
||||||
|
items_per_page: 10
|
||||||
|
total_pages: null
|
||||||
|
id: 0
|
||||||
|
tags:
|
||||||
|
next: ››
|
||||||
|
previous: ‹‹
|
||||||
|
expose:
|
||||||
|
items_per_page: false
|
||||||
|
items_per_page_label: 'Items per page'
|
||||||
|
items_per_page_options: '5, 10, 25, 50'
|
||||||
|
items_per_page_options_all: false
|
||||||
|
items_per_page_options_all_label: '- All -'
|
||||||
|
offset: false
|
||||||
|
offset_label: Offset
|
||||||
|
exposed_form:
|
||||||
|
type: basic
|
||||||
|
options:
|
||||||
|
submit_button: Apply
|
||||||
|
reset_button: false
|
||||||
|
reset_button_label: Reset
|
||||||
|
exposed_sorts_label: 'Sort by'
|
||||||
|
expose_sort_order: true
|
||||||
|
sort_asc_label: Asc
|
||||||
|
sort_desc_label: Desc
|
||||||
|
access:
|
||||||
|
type: perm
|
||||||
|
options:
|
||||||
|
perm: 'access content'
|
||||||
|
cache:
|
||||||
|
type: tag
|
||||||
|
options: { }
|
||||||
|
empty: { }
|
||||||
|
sorts:
|
||||||
|
field_episode_number_value:
|
||||||
|
id: field_episode_number_value
|
||||||
|
table: node__field_episode_number
|
||||||
|
field: field_episode_number_value
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
plugin_id: standard
|
||||||
|
order: DESC
|
||||||
|
expose:
|
||||||
|
label: ''
|
||||||
|
field_identifier: ''
|
||||||
|
exposed: false
|
||||||
|
arguments: { }
|
||||||
|
filters:
|
||||||
|
status:
|
||||||
|
id: status
|
||||||
|
table: node_field_data
|
||||||
|
field: status
|
||||||
|
entity_type: node
|
||||||
|
entity_field: status
|
||||||
|
plugin_id: boolean
|
||||||
|
value: '1'
|
||||||
|
group: 1
|
||||||
|
expose:
|
||||||
|
operator: ''
|
||||||
|
type:
|
||||||
|
id: type
|
||||||
|
table: node_field_data
|
||||||
|
field: type
|
||||||
|
entity_type: node
|
||||||
|
entity_field: type
|
||||||
|
plugin_id: bundle
|
||||||
|
value:
|
||||||
|
podcast_episode: podcast_episode
|
||||||
|
style:
|
||||||
|
type: default
|
||||||
|
row:
|
||||||
|
type: 'entity:node'
|
||||||
|
options:
|
||||||
|
relationship: none
|
||||||
|
view_mode: teaser
|
||||||
|
query:
|
||||||
|
type: views_query
|
||||||
|
options:
|
||||||
|
query_comment: ''
|
||||||
|
disable_sql_rewrite: false
|
||||||
|
distinct: false
|
||||||
|
replica: false
|
||||||
|
query_tags: { }
|
||||||
|
relationships: { }
|
||||||
|
header:
|
||||||
|
area:
|
||||||
|
id: area
|
||||||
|
table: views
|
||||||
|
field: area
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
plugin_id: text
|
||||||
|
empty: false
|
||||||
|
content:
|
||||||
|
value: "<p>A podcast about Drupal, PHP, open-source, and related software development topics.\r\nGuests include people like <a href=\"/podcast/1-retrofit\">Matt Glaman</a>, <a href=\"/podcast/8-eirik-morland-violinist\">Eirik Morland</a>, <a href=\"/podcast/9-tim-lehnen\">Tim Lehnen</a>, <a href=\"/podcast/13-ryan-szrama-centarro\">Ryan Szrama</a>, <a href=\"/podcast/19-sam-mortenson\">Sam Mortenson</a> and <a href=\"/podcast/25-jess-archer-drush-laravel-prompts\">Jess Archer</a>.</p>"
|
||||||
|
format: basic_html
|
||||||
|
tokenize: false
|
||||||
|
footer: { }
|
||||||
|
display_extenders: { }
|
||||||
|
cache_metadata:
|
||||||
|
max-age: -1
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
tags: { }
|
||||||
|
page_1:
|
||||||
|
id: page_1
|
||||||
|
display_title: Page
|
||||||
|
display_plugin: page
|
||||||
|
position: 1
|
||||||
|
display_options:
|
||||||
|
display_extenders: { }
|
||||||
|
path: podcast
|
||||||
|
cache_metadata:
|
||||||
|
max-age: -1
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
tags: { }
|
5
modules/opd_podcast/opd_podcast.info.yml
Normal file
5
modules/opd_podcast/opd_podcast.info.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
name: Podcast
|
||||||
|
description: Custom functionality for podcasts.
|
||||||
|
core_version_requirement: ^11
|
||||||
|
type: module
|
||||||
|
package: Custom
|
21
modules/opd_podcast/opd_podcast.module
Normal file
21
modules/opd_podcast/opd_podcast.module
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Drupal\node\NodeInterface;
|
||||||
|
|
||||||
|
function opd_podcast_node_links_alter(array &$links, NodeInterface $entity, array &$context): void {
|
||||||
|
if ($entity->bundle() !== 'podcast_episode') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$links['node']['#links']['node-readmore']['title'] = t('Listen now<span class="visually-hidden"> to @title</span> →');
|
||||||
|
|
||||||
|
$links['node']['#links']['node-readmore']['attributes']['class'] = [
|
||||||
|
'p-0',
|
||||||
|
];
|
||||||
|
|
||||||
|
$links['#attributes']['class'][] = 'list-none';
|
||||||
|
$links['#attributes']['class'][] = 'm-0';
|
||||||
|
$links['#attributes']['class'][] = 'p-0';
|
||||||
|
}
|
|
@ -1620,6 +1620,11 @@ select {
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.my-2 {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.my-4 {
|
.my-4 {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
@ -1913,6 +1918,12 @@ select {
|
||||||
margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse)));
|
margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.space-y-6 > :not([hidden]) ~ :not([hidden]) {
|
||||||
|
--tw-space-y-reverse: 0;
|
||||||
|
margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
|
||||||
|
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
|
||||||
|
}
|
||||||
|
|
||||||
.space-y-10 > :not([hidden]) ~ :not([hidden]) {
|
.space-y-10 > :not([hidden]) ~ :not([hidden]) {
|
||||||
--tw-space-y-reverse: 0;
|
--tw-space-y-reverse: 0;
|
||||||
margin-top: calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));
|
margin-top: calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));
|
||||||
|
@ -2909,4 +2920,3 @@ select {
|
||||||
border-color: rgb(168 162 158 / var(--tw-border-opacity));
|
border-color: rgb(168 162 158 / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
3
themes/opdavies/css/overrides.css
Normal file
3
themes/opdavies/css/overrides.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
ul.links.inline > li {
|
||||||
|
padding: 0;
|
||||||
|
}
|
|
@ -2,3 +2,4 @@ global-styling:
|
||||||
css:
|
css:
|
||||||
base:
|
base:
|
||||||
build/tailwind.css: {}
|
build/tailwind.css: {}
|
||||||
|
css/overrides.css: {}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
{#
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Default theme implementation to display a node.
|
||||||
|
*
|
||||||
|
* Available variables:
|
||||||
|
* - node: The node entity with limited access to object properties and methods.
|
||||||
|
* Only method names starting with "get", "has", or "is" and a few common
|
||||||
|
* methods such as "id", "label", and "bundle" are available. For example:
|
||||||
|
* - node.getCreatedTime() will return the node creation timestamp.
|
||||||
|
* - node.hasField('field_example') returns TRUE if the node bundle includes
|
||||||
|
* field_example. (This does not indicate the presence of a value in this
|
||||||
|
* field.)
|
||||||
|
* - node.isPublished() will return whether the node is published or not.
|
||||||
|
* Calling other methods, such as node.delete(), will result in an exception.
|
||||||
|
* See \Drupal\node\Entity\Node for a full list of public properties and
|
||||||
|
* methods for the node object.
|
||||||
|
* - label: (optional) The title of the node.
|
||||||
|
* - content: All node items. Use {{ content }} to print them all,
|
||||||
|
* or print a subset such as {{ content.field_example }}. Use
|
||||||
|
* {{ content|without('field_example') }} to temporarily suppress the printing
|
||||||
|
* of a given child element.
|
||||||
|
* - author_picture: The node author user entity, rendered using the "compact"
|
||||||
|
* view mode.
|
||||||
|
* - date: (optional) Themed creation date field.
|
||||||
|
* - author_name: (optional) Themed author name field.
|
||||||
|
* - url: Direct URL of the current node.
|
||||||
|
* - display_submitted: Whether submission information should be displayed.
|
||||||
|
* - attributes: HTML attributes for the containing element.
|
||||||
|
* The attributes.class element may contain one or more of the following
|
||||||
|
* classes:
|
||||||
|
* - node: The current template type (also known as a "theming hook").
|
||||||
|
* - node--type-[type]: The current node type. For example, if the node is an
|
||||||
|
* "Article" it would result in "node--type-article". Note that the machine
|
||||||
|
* name will often be in a short form of the human readable label.
|
||||||
|
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
|
||||||
|
* teaser would result in: "node--view-mode-teaser", and
|
||||||
|
* full: "node--view-mode-full".
|
||||||
|
* The following are controlled through the node publishing options.
|
||||||
|
* - node--promoted: Appears on nodes promoted to the front page.
|
||||||
|
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
|
||||||
|
* teaser listings.
|
||||||
|
* - node--unpublished: Appears on unpublished nodes visible only to site
|
||||||
|
* admins.
|
||||||
|
* - title_attributes: Same as attributes, except applied to the main title
|
||||||
|
* tag that appears in the template.
|
||||||
|
* - content_attributes: Same as attributes, except applied to the main
|
||||||
|
* content tag that appears in the template.
|
||||||
|
* - author_attributes: Same as attributes, except applied to the author of
|
||||||
|
* the node tag that appears in the template.
|
||||||
|
* - title_prefix: Additional output populated by modules, intended to be
|
||||||
|
* displayed in front of the main title tag that appears in the template.
|
||||||
|
* - title_suffix: Additional output populated by modules, intended to be
|
||||||
|
* displayed after the main title tag that appears in the template.
|
||||||
|
* - view_mode: View mode; for example, "teaser" or "full".
|
||||||
|
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
|
||||||
|
*
|
||||||
|
* @see template_preprocess_node()
|
||||||
|
*
|
||||||
|
* @ingroup themeable
|
||||||
|
*/
|
||||||
|
#}
|
||||||
|
<article{{ attributes }}>
|
||||||
|
{{ title_prefix }}
|
||||||
|
{% if label and not page %}
|
||||||
|
<h2{{ title_attributes.addClass('font-bold text-xl') }}>
|
||||||
|
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
|
||||||
|
</h2>
|
||||||
|
{% endif %}
|
||||||
|
{{ title_suffix }}
|
||||||
|
|
||||||
|
<div class="prose prose-p:text-black prose-a:font-light prose-a:text-blue-primary prose-p:text-lg prose-blockquote:border-blue-primary dark:marker:text-white prose-li:my-1 prose-li:text-lg prose-figcaption:text-white prose-li:text-black marker:text-black dark:prose-p:text-white dark:prose-invert dark:prose-a:text-blue-400 dark:prose-blockquote:border-blue-400 dark:prose-li:text-white hover:prose-a:no-underline prose-h2:text-xl prose-code:font-normal prose-h2:mb-4 prose-ul:my-3 dark:prose-hr:border-grey-400 prose-code:before:content-[''] prose-code:after:content-['']">
|
||||||
|
{% if display_submitted %}
|
||||||
|
<div class="my-2 text-base">
|
||||||
|
{% set created = node.getCreatedTime() %}
|
||||||
|
|
||||||
|
<time datetime="{{ created|format_date('html_date') }}">{{ created|format_date('short') }}</time>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div{{ content_attributes.addClass('mt-2') }}>
|
||||||
|
{{ content|without('links') }}
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
{{ content.links }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
|
@ -0,0 +1,78 @@
|
||||||
|
{#
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Default theme implementation for main view template.
|
||||||
|
*
|
||||||
|
* Available variables:
|
||||||
|
* - attributes: Remaining HTML attributes for the element.
|
||||||
|
* - css_name: A CSS-safe version of the view name.
|
||||||
|
* - css_class: The user-specified classes names, if any.
|
||||||
|
* - header: The optional header.
|
||||||
|
* - footer: The optional footer.
|
||||||
|
* - rows: The results of the view query, if any.
|
||||||
|
* - empty: The content to display if there are no rows.
|
||||||
|
* - pager: The optional pager next/prev links to display.
|
||||||
|
* - exposed: Exposed widget form/info to display.
|
||||||
|
* - feed_icons: Optional feed icons to display.
|
||||||
|
* - more: An optional link to the next page of results.
|
||||||
|
* - title: Title of the view, only used when displaying in the admin preview.
|
||||||
|
* - title_prefix: Additional output populated by modules, intended to be
|
||||||
|
* displayed in front of the view title.
|
||||||
|
* - title_suffix: Additional output populated by modules, intended to be
|
||||||
|
* displayed after the view title.
|
||||||
|
* - attachment_before: An optional attachment view to be displayed before the
|
||||||
|
* view content.
|
||||||
|
* - attachment_after: An optional attachment view to be displayed after the
|
||||||
|
* view content.
|
||||||
|
* - dom_id: Unique id for every view being printed to give unique class for
|
||||||
|
* JavaScript.
|
||||||
|
*
|
||||||
|
* @see template_preprocess_views_view()
|
||||||
|
*
|
||||||
|
* @ingroup themeable
|
||||||
|
*/
|
||||||
|
#}
|
||||||
|
{%
|
||||||
|
set classes = [
|
||||||
|
dom_id ? 'js-view-dom-id-' ~ dom_id,
|
||||||
|
]
|
||||||
|
%}
|
||||||
|
<div{{ attributes.addClass(classes) }}>
|
||||||
|
{{ title_prefix }}
|
||||||
|
{{ title }}
|
||||||
|
{{ title_suffix }}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{% if header %}
|
||||||
|
<header class="prose prose-p:text-black prose-a:font-light prose-a:text-blue-primary prose-p:text-lg prose-blockquote:border-blue-primary dark:marker:text-white prose-li:my-1 prose-li:text-lg prose-figcaption:text-white prose-li:text-black marker:text-black dark:prose-p:text-white dark:prose-invert dark:prose-a:text-blue-400 dark:prose-blockquote:border-blue-400 dark:prose-li:text-white hover:prose-a:no-underline prose-h2:text-xl prose-code:font-normal prose-h2:mb-4 prose-ul:my-3 dark:prose-hr:border-grey-400 prose-code:before:content-[''] prose-code:after:content-['']">
|
||||||
|
{{ header }}
|
||||||
|
</header>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ exposed }}
|
||||||
|
{{ attachment_before }}
|
||||||
|
|
||||||
|
{% if rows -%}
|
||||||
|
<div class="mt-10">
|
||||||
|
<div class="space-y-8">
|
||||||
|
{{ rows }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% elseif empty -%}
|
||||||
|
{{ empty }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ pager }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ attachment_after }}
|
||||||
|
{{ more }}
|
||||||
|
|
||||||
|
{% if footer %}
|
||||||
|
<footer>
|
||||||
|
{{ footer }}
|
||||||
|
</footer>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ feed_icons }}
|
||||||
|
</div>
|
Loading…
Add table
Add a link
Reference in a new issue