├── .docker-config ├── nginx │ ├── Dockerfile │ └── default.conf ├── node-dev-vite │ ├── Dockerfile │ └── npm_install.sh ├── php-dev-craft │ └── Dockerfile ├── php-prod-craft │ ├── Dockerfile │ ├── composer_install.sh │ └── run_queue.sh ├── postgres │ └── Dockerfile └── redis │ └── Dockerfile ├── .dockerignore ├── .github └── CODEOWNERS ├── CHANGELOG.md ├── LICENSE.md ├── Makefile ├── README.md ├── buddy.yml ├── buildchain ├── eslint.config.js ├── package-lock.json ├── package.json ├── src │ ├── css │ │ ├── app.css │ │ ├── components │ │ │ ├── fontello-codes.css │ │ │ ├── global.css │ │ │ ├── range-slider.css │ │ │ ├── tables.css │ │ │ ├── typography.css │ │ │ ├── webfonts.css │ │ │ └── webmentions.css │ │ ├── pages │ │ │ └── homepage.css │ │ ├── tailwind-config.css │ │ └── vendor.css │ ├── fontello │ │ ├── .gitkeep │ │ └── config.json │ ├── img │ │ ├── devmodefm-social-media.png │ │ └── favicon-src.png │ ├── js │ │ ├── @types │ │ │ └── shims.d.ts │ │ ├── app.ts │ │ ├── modules │ │ │ ├── episodes.js │ │ │ └── player.js │ │ └── utils │ │ │ ├── lazy-load-component.js │ │ │ └── lazysizes-wrapper.ts │ ├── public │ │ └── fonts │ │ │ ├── OperatorMonoSSm-Book.eot │ │ │ ├── OperatorMonoSSm-Book.ttf │ │ │ ├── OperatorMonoSSm-Book.woff │ │ │ ├── OperatorMonoSSm-Book.woff2 │ │ │ ├── OperatorMonoSSm-BookItalic.eot │ │ │ ├── OperatorMonoSSm-BookItalic.ttf │ │ │ ├── OperatorMonoSSm-BookItalic.woff │ │ │ ├── OperatorMonoSSm-BookItalic.woff2 │ │ │ ├── fontello.eot │ │ │ ├── fontello.svg │ │ │ ├── fontello.ttf │ │ │ ├── fontello.woff │ │ │ └── fontello.woff2 │ └── vue │ │ ├── @types │ │ └── shims-vue.d.ts │ │ ├── DevmodePlayer.vue │ │ ├── EpisodeCell.vue │ │ ├── EpisodesFieldDefs.js │ │ ├── EpisodesTable.vue │ │ ├── PlayerSkeletonBox.vue │ │ ├── SkeletonBox.vue │ │ ├── VueTable.vue │ │ ├── VuetableFilterBar.vue │ │ ├── VuetablePagination.vue │ │ ├── VuetablePaginationInfo.vue │ │ ├── VuetablePaginationInfoMixin.vue │ │ └── VuetablePaginationMixin.vue ├── stylelint.config.js ├── tsconfig.json └── vite.config.ts ├── cms ├── bootstrap.php ├── composer.json ├── composer.lock ├── config │ ├── app.console.php │ ├── app.php │ ├── app.web.php │ ├── custom.php │ ├── db.php │ ├── fastcgi-cache-bust.php │ ├── general.php │ ├── image-optimize.php │ ├── project │ │ ├── addresses │ │ │ └── fieldLayouts │ │ │ │ └── 81eddbf6-097d-49f3-8bf9-6ed21bb8bcac.yaml │ │ ├── entryTypes │ │ │ ├── about--cc4ea2bd-3bde-4bad-8f72-272fcc3c2a19.yaml │ │ │ ├── calendar--7f6ad724-41b7-4a93-bef9-7de87d1bb23e.yaml │ │ │ ├── episodes--913ea665-c268-4177-8054-fe76f80101c6.yaml │ │ │ ├── episodesIndex--50012289-791c-48b2-8df1-31a8f5eb5380.yaml │ │ │ ├── faqs--a009e969-e0ed-429e-9ab3-98561af05518.yaml │ │ │ ├── genericError--e81379aa-e0c7-45c0-b506-c4ab8fce6bce.yaml │ │ │ ├── guests--032dc0eb-27cf-4034-ad36-dc8c274a455e.yaml │ │ │ ├── homepage--9aae2c4b-7316-4ee9-a2d1-41474766b361.yaml │ │ │ ├── notFound--78ad1f1e-5dc5-4cff-b19f-43aa4ec02869.yaml │ │ │ ├── serviceUnavailable--29da80bf-c705-441b-be33-96df307c84c6.yaml │ │ │ └── siteOffline--a4be3483-f316-4f96-8820-3914ad7b863a.yaml │ │ ├── fields │ │ │ ├── answer--2bb6f342-1735-446e-b9fe-754f94dac82f.yaml │ │ │ ├── episodeGuests--7e338b73-ac10-44cf-892e-04afc0164991.yaml │ │ │ ├── episodeHosts--a5cf9c0d-1797-4a60-8c47-bc28c5f01a95.yaml │ │ │ ├── episodeMedia--0090f7a3-1e22-4fb5-9ae0-01de38805601.yaml │ │ │ ├── episodeNumber--324e7a11-3346-41e7-a29d-4636ab907e51.yaml │ │ │ ├── episodeReferenceLinks--8c9dd611-b43b-4e22-b076-3f6a6362c93e.yaml │ │ │ ├── episodeSummary--8011817c-9518-4a31-9aa8-cad6d4a08b81.yaml │ │ │ ├── episodeTags--61953a92-8b34-4678-9bae-fd5a45142f26.yaml │ │ │ ├── episodeTranscript--523395ea-5738-4ca5-a119-f32221ea5ca8.yaml │ │ │ ├── errorHeadline--18d7721b-780b-4a44-976a-716c3df0bb7a.yaml │ │ │ ├── errorImage--4d90d0e7-b705-4035-b396-2f82ce5bb871.yaml │ │ │ ├── errorText--e1087165-5769-428d-bf14-c98e6011cf5e.yaml │ │ │ ├── faqs--b5eb01ec-a6ed-4a08-9438-64e7138b08f0.yaml │ │ │ ├── links--98dbc824-8c89-4138-9b0f-011a96875a7a.yaml │ │ │ ├── optimizedImages--1be1c156-82fa-4f08-bb63-6d3417da2844.yaml │ │ │ ├── profileBio--9687721c-33b8-4a40-abb7-5c42e07ce274.yaml │ │ │ ├── profileCompany--c05161c0-a294-4d47-8909-1cfc88c2f970.yaml │ │ │ ├── profileGithubUrl--d6df6fe7-14f3-42a3-9949-dcee7c8c26d9.yaml │ │ │ ├── profileOptimizedImages--41fdb4c8-4774-4101-918f-1412190b085b.yaml │ │ │ ├── profileTitle--380e3b7e-07de-4d39-b0e5-360f5e87d00d.yaml │ │ │ ├── profileTwitterUrl--406c20cb-9b86-4b0d-9123-1ce57220e2a8.yaml │ │ │ ├── profileUrl--31b8c511-37f9-4d83-956d-5aa215572122.yaml │ │ │ ├── question--e0264ea5-7834-42de-9f8f-c611149453d0.yaml │ │ │ ├── relatedEpisodes--07f04bdf-277d-4010-9fbe-497cd9593324.yaml │ │ │ ├── showDescription--86909527-3ec4-4d57-a44c-167649eb86bf.yaml │ │ │ ├── showEmail--ca279869-925f-4960-865c-96cacd2aa942.yaml │ │ │ ├── showGenre--6def66f0-2a8f-4b88-9435-7f9cc1ccfe9c.yaml │ │ │ ├── showImage--bda219fa-bace-4d8b-ad3a-08243caaf6ca.yaml │ │ │ ├── showItunesUrl--14605669-4768-4f57-88d6-1f06480a9b80.yaml │ │ │ ├── showRssFeedUrl--ab0ca0e9-1308-472f-92a5-2ab0cbd84943.yaml │ │ │ ├── showSubTitle--2405ed1c-fd52-4264-a96a-f6e6fab437b5.yaml │ │ │ ├── showTechnologiesLinks--eecc24bf-e253-43b8-b327-632e0dc07fa6.yaml │ │ │ ├── showTitle--a8f2ec1a-a218-451c-a658-e3c600ddb5fa.yaml │ │ │ └── showUrl--428ec106-b2d1-4d48-a5fa-de192155dff5.yaml │ │ ├── globalSets │ │ │ └── showInfo--087ee23d-4f8f-42d4-af12-99fcc2462247.yaml │ │ ├── project.yaml │ │ ├── sections │ │ │ ├── about--486a0853-47b2-4509-97ad-43fe3ec42074.yaml │ │ │ ├── calendar--a1eaefb7-b32a-436d-a218-3fc7be02c917.yaml │ │ │ ├── episodes--c1f6af30-7375-4feb-92ef-a3ed16ba69b2.yaml │ │ │ ├── episodesIndex--1a66bf43-6fcc-4a78-bf36-0f350b930430.yaml │ │ │ ├── genericError--519413e8-a432-4cfe-98c5-5f81e9519f2a.yaml │ │ │ ├── guests--214e4dc6-a454-4df0-a1f5-cd94ecdab53f.yaml │ │ │ ├── homepage--a9d3a609-1f18-4cb7-afc3-3c103a7e09de.yaml │ │ │ ├── notFound--52b673e7-3d80-44a4-94f7-43eaafcc9d6f.yaml │ │ │ ├── serviceUnavailable--9089688f-6602-4d69-91cd-ec9a94c4bc6f.yaml │ │ │ └── siteOffline--5f70b9e0-f42b-4fdb-bcf6-5e82691d89de.yaml │ │ ├── siteGroups │ │ │ └── 34348a98-83b9-4f2d-8e14-0437ec964a15.yaml │ │ ├── sites │ │ │ └── default--2a4761bd-2461-4db9-96a0-4f52b8cef633.yaml │ │ ├── tagGroups │ │ │ └── episodes--fc24a736-c435-4d8a-aeb3-6105afce1d91.yaml │ │ ├── users │ │ │ ├── fieldLayouts │ │ │ │ └── 414459bf-ed39-4493-916d-6a00213bce60.yaml │ │ │ ├── groups │ │ │ │ ├── hosts--19dfdfbb-837c-46d5-87bf-e6540df98dc4.yaml │ │ │ │ └── owners--9436ac5e-44de-4fe9-be59-fd1f0fc26941.yaml │ │ │ └── users.yaml │ │ └── volumes │ │ │ ├── devmodeEpisodes--e69c8edb-d562-4367-9a05-91a6fd2c7d99.yaml │ │ │ ├── devmodeSite--7540db37-7ec3-4471-9de6-36bde06e949a.yaml │ │ │ ├── devmodeTranscripts--bd8ef0d7-f73b-4138-ac52-c14d11dd780e.yaml │ │ │ └── devmodeUsers--98f56e95-4be6-4238-a110-1f21574fa642.yaml │ ├── redactor │ │ ├── Simple.json │ │ └── Standard.json │ ├── routes.php │ ├── seomatic-config │ │ └── globalmeta │ │ │ └── Creator.php │ ├── transcoder.php │ ├── twigpack.php │ ├── typogrify.php │ └── vite.php ├── craft ├── craft.bat ├── example.env ├── modules │ └── sitemodule │ │ ├── .craftplugin │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE.md │ │ ├── README.md │ │ └── src │ │ ├── SiteModule.php │ │ ├── assetbundles │ │ └── sitemodule │ │ │ ├── SiteModuleAsset.php │ │ │ └── dist │ │ │ ├── css │ │ │ └── SiteModule.css │ │ │ ├── img │ │ │ └── SiteModule-icon.svg │ │ │ └── js │ │ │ └── SiteModule.js │ │ ├── config.php │ │ ├── controllers │ │ └── SiteController.php │ │ ├── helpers │ │ └── Config.php │ │ ├── services │ │ ├── Calendar.php │ │ ├── RemoteFile.php │ │ └── Transcript.php │ │ ├── translations │ │ └── en │ │ │ └── site-module.php │ │ └── variables │ │ └── SiteVariable.php ├── templates │ ├── .gitkeep │ ├── _boilerplate │ │ ├── _layouts │ │ │ ├── amp-base-html-layout.twig │ │ │ ├── base-ajax-layout.twig │ │ │ ├── base-html-layout.twig │ │ │ └── base-web-layout.twig │ │ └── _partials │ │ │ ├── amp-analytics.twig │ │ │ ├── amp-boilerplate-css.twig │ │ │ ├── amp-head-js.twig │ │ │ ├── body-js.twig │ │ │ ├── critical-css.twig │ │ │ ├── head-js.twig │ │ │ ├── head-meta.twig │ │ │ ├── register-service-worker.twig │ │ │ └── tab-handler.twig │ ├── _inline-css │ │ └── site-fonts.css │ ├── _inline-js │ │ ├── lazyload-image-shim.js │ │ └── tiny-cookie.min.js │ ├── _layouts │ │ ├── amp-generic-page-layout.twig │ │ ├── error-page-layout.twig │ │ ├── generic-page-layout.twig │ │ ├── global-variables.twig │ │ └── player-page-layout.twig │ ├── _partials │ │ ├── _meta-schema-radio-series.twig │ │ ├── amp-info-footer.twig │ │ ├── amp-info-header.twig │ │ ├── amp-inline-css.css │ │ ├── amp-navbar.twig │ │ ├── amp-webmentions-facepile.twig │ │ ├── global-footer.twig │ │ ├── info-footer.twig │ │ ├── info-header.twig │ │ ├── macros.twig │ │ ├── navbar.twig │ │ └── webmentions-facepile.twig │ ├── about │ │ ├── _partials │ │ │ ├── _amp_display_host_excerpt.twig │ │ │ ├── _display_host_excerpt.twig │ │ │ └── _meta-schema-faqpage.twig │ │ ├── amp-index.twig │ │ └── index.twig │ ├── amp-index.twig │ ├── calendar │ │ ├── _partials │ │ │ └── _display_event_excerpt.twig │ │ ├── amp-index.twig │ │ └── index.twig │ ├── episodes │ │ ├── _amp-entry.twig │ │ ├── _entry.twig │ │ ├── _partials │ │ │ ├── _amp_display_episode.twig │ │ │ ├── _amp_display_episode_excerpt.twig │ │ │ ├── _amp_display_player.twig │ │ │ ├── _amp_display_recent_episodes.twig │ │ │ ├── _display_episode.twig │ │ │ ├── _display_episode_excerpt.twig │ │ │ ├── _display_player.twig │ │ │ ├── _display_recent_episodes.twig │ │ │ ├── _display_transcript.twig │ │ │ ├── _meta-episode-custom.twig │ │ │ ├── _meta-og-audio.twig │ │ │ ├── _meta-schema-audio.twig │ │ │ └── _meta-twitter-player-card.twig │ │ ├── amp-index.twig │ │ └── index.twig │ ├── errors │ │ ├── 404.twig │ │ ├── 503.twig │ │ ├── error.twig │ │ └── offline.twig │ ├── feed.json │ ├── index.twig │ ├── player-card.twig │ └── rss.twig └── web │ ├── .gitkeep │ ├── .htaccess │ ├── img │ ├── .gitkeep │ ├── devmodefm-social-media.png │ ├── favicon_src.png │ └── site │ │ ├── devmode-fm-dark-bg.svg │ │ ├── devmode-fm-light-bg-opaque.svg │ │ └── devmode-fm-light-bg.svg │ ├── index.php │ ├── js │ └── analytics.js │ └── web.config ├── db-seed ├── .gitignore ├── db_init.sh └── dbs │ └── project.sql.gz ├── docker-compose.yml └── scripts ├── common ├── common_db.sh ├── common_env.sh ├── common_mysql.sh ├── common_pgsql.sh └── defaults.sh ├── docker_pull_db.sh ├── docker_restore_db.sh └── example.env.sh /.docker-config/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.19-alpine 2 | 3 | COPY ./default.conf /etc/nginx/conf.d/default.conf 4 | -------------------------------------------------------------------------------- /.docker-config/nginx/default.conf: -------------------------------------------------------------------------------- 1 | # default Docker DNS server 2 | resolver 127.0.0.11; 3 | 4 | # If a cookie doesn't exist, it evaluates to an empty string, so if neither cookie exists, it'll match : 5 | # (empty string on either side of the :), but if either or both cookies are set, it won't match, and will hit the default rule 6 | map $cookie_XDEBUG_SESSION:$cookie_XDEBUG_PROFILE $my_fastcgi_pass { 7 | default php_xdebug; 8 | ':' php; 9 | } 10 | 11 | server { 12 | listen 80; 13 | listen [::]:80; 14 | 15 | server_name _; 16 | root /var/www/project/cms/web; 17 | index index.html index.htm index.php; 18 | charset utf-8; 19 | 20 | gzip_static on; 21 | 22 | ssi on; 23 | 24 | client_max_body_size 0; 25 | 26 | error_page 404 /index.php?$query_string; 27 | 28 | access_log off; 29 | error_log /dev/stdout info; 30 | 31 | location / { 32 | try_files $uri/index.html $uri $uri/ /index.php?$query_string; 33 | } 34 | 35 | location ~ [^/]\.php(/|$) { 36 | try_files $uri $uri/ /index.php?$query_string; 37 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 38 | fastcgi_pass $my_fastcgi_pass:9000; 39 | fastcgi_index index.php; 40 | include fastcgi_params; 41 | fastcgi_param PATH_INFO $fastcgi_path_info; 42 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; 43 | fastcgi_param DOCUMENT_ROOT $realpath_root; 44 | fastcgi_param HTTP_PROXY ""; 45 | 46 | add_header Last-Modified $date_gmt; 47 | add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0"; 48 | if_modified_since off; 49 | expires off; 50 | etag off; 51 | 52 | fastcgi_intercept_errors off; 53 | fastcgi_buffer_size 16k; 54 | fastcgi_buffers 4 16k; 55 | fastcgi_connect_timeout 300; 56 | fastcgi_send_timeout 300; 57 | fastcgi_read_timeout 300; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /.docker-config/node-dev-vite/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nystudio107/node-dev-base:22-alpine 2 | 3 | RUN npm install -g npm@^11.0.0 4 | 5 | WORKDIR /var/www/project/ 6 | 7 | # Install packages 8 | RUN set -eux; \ 9 | # Packages to install 10 | apk add --no-cache \ 11 | git \ 12 | && \ 13 | # Clean out directories that don't need to be part of the image 14 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 15 | 16 | COPY ./npm_install.sh . 17 | RUN chmod a+x npm_install.sh 18 | 19 | WORKDIR /var/www/project/buildchain 20 | 21 | # Run our webpack build in debug mode 22 | 23 | # We'd normally use `npm ci` here, but by using `install`: 24 | # - If `package-lock.json` is present, it will install what is in the lock file 25 | # - If `package-lock.json` is missing, it will update to the latest dependencies 26 | # and create the `package-lock-json` file 27 | # This automatic running adds to the startup overhead of `docker-compose up` 28 | # but saves far more time in not having to deal with out of sync versions 29 | # when working with teams or multiple environments 30 | CMD export CPPFLAGS="-DPNG_ARM_NEON_OPT=0" \ 31 | && \ 32 | /var/www/project/npm_install.sh \ 33 | && \ 34 | npm run dev 35 | -------------------------------------------------------------------------------- /.docker-config/node-dev-vite/npm_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # NPM Install shell script 4 | # 5 | # This shell script runs `npm install` if either the `package-lock.json` file or 6 | # the `node_modules/` directory is not present` 7 | # 8 | # @author nystudio107 9 | # @copyright Copyright (c) 2022 nystudio107 10 | # @link https://nystudio107.com/ 11 | # @license MIT 12 | 13 | cd /var/www/project/buildchain 14 | if [ ! -f "package-lock.json" ] || [ ! -d "node_modules" ]; then 15 | npm install 16 | fi 17 | -------------------------------------------------------------------------------- /.docker-config/php-dev-craft/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nystudio107/php-dev-base:8.2-alpine 2 | 3 | # dependencies required for running "phpize" 4 | # these get automatically installed and removed by "docker-php-ext-*" (unless they're already installed) 5 | ENV PHPIZE_DEPS \ 6 | autoconf \ 7 | dpkg-dev dpkg \ 8 | file \ 9 | g++ \ 10 | gcc \ 11 | libc-dev \ 12 | make \ 13 | pkgconf \ 14 | re2c \ 15 | wget 16 | 17 | # Install packages 18 | RUN set -eux; \ 19 | # Packages needed only for build 20 | apk add --no-cache --virtual .build-deps \ 21 | $PHPIZE_DEPS \ 22 | && \ 23 | # Packages to install 24 | apk add --no-cache \ 25 | bash \ 26 | su-exec \ 27 | ffmpeg \ 28 | gifsicle \ 29 | jpegoptim \ 30 | libwebp-tools \ 31 | nano \ 32 | optipng \ 33 | postgresql-client \ 34 | postgresql-dev \ 35 | && \ 36 | # Install PHP extensions 37 | docker-php-ext-install \ 38 | pdo_pgsql \ 39 | pgsql \ 40 | && \ 41 | # Install Composer 42 | curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin/ --filename=composer \ 43 | && \ 44 | # Remove the build deps 45 | apk del .build-deps \ 46 | && \ 47 | # Clean out directories that don't need to be part of the image 48 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 49 | 50 | WORKDIR /var/www/project 51 | 52 | RUN mkdir -p /var/www/project/cms/storage \ 53 | && \ 54 | mkdir -p /var/www/project/cms/web/cpresources \ 55 | && \ 56 | chown -R www-data:www-data /var/www/project 57 | 58 | WORKDIR /var/www/project/cms 59 | 60 | # Start php-fpm 61 | CMD php-fpm 62 | -------------------------------------------------------------------------------- /.docker-config/php-prod-craft/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nystudio107/php-prod-base:8.2-alpine 2 | 3 | # dependencies required for running "phpize" 4 | # these get automatically installed and removed by "docker-php-ext-*" (unless they're already installed) 5 | ENV PHPIZE_DEPS \ 6 | autoconf \ 7 | dpkg-dev dpkg \ 8 | file \ 9 | g++ \ 10 | gcc \ 11 | libc-dev \ 12 | make \ 13 | pkgconf \ 14 | re2c \ 15 | wget 16 | 17 | # Install packages 18 | RUN set -eux; \ 19 | # Packages needed only for build 20 | apk add --no-cache --virtual .build-deps \ 21 | $PHPIZE_DEPS \ 22 | && \ 23 | # Packages to install 24 | apk add --no-cache \ 25 | bash \ 26 | su-exec \ 27 | ffmpeg \ 28 | gifsicle \ 29 | jpegoptim \ 30 | libwebp-tools \ 31 | nano \ 32 | optipng \ 33 | postgresql-client \ 34 | postgresql-dev \ 35 | && \ 36 | # Install PHP extensions 37 | docker-php-ext-install \ 38 | pdo_pgsql \ 39 | pgsql \ 40 | && \ 41 | # Install Composer 42 | curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin/ --filename=composer \ 43 | && \ 44 | # Remove the build deps 45 | apk del .build-deps \ 46 | && \ 47 | # Clean out directories that don't need to be part of the image 48 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 49 | 50 | WORKDIR /var/www/project 51 | 52 | COPY ./run_queue.sh . 53 | RUN chmod a+x run_queue.sh \ 54 | && \ 55 | mkdir -p /var/www/project/cms/storage \ 56 | && \ 57 | mkdir -p /var/www/project/cms/web/cpresources \ 58 | && \ 59 | chown -R www-data:www-data /var/www/project 60 | COPY ./composer_install.sh . 61 | RUN chmod a+x composer_install.sh 62 | 63 | WORKDIR /var/www/project/cms 64 | 65 | # Run the composer_install.sh script that will do a `composer install`: 66 | # - If `composer.lock` is missing 67 | # - If `vendor/` is missing 68 | # ...then start up php-fpm. The `run_queue.sh` script in the queue container 69 | # will take care of running any pending migrations and apply any Project Config changes, 70 | # as well as set permissions via an async CLI process 71 | CMD /var/www/project/composer_install.sh \ 72 | && \ 73 | php-fpm 74 | -------------------------------------------------------------------------------- /.docker-config/php-prod-craft/composer_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Composer Install shell script 4 | # 5 | # This shell script runs `composer install` if either the `composer.lock` file or 6 | # the `vendor/` directory is not present` 7 | # 8 | # @author nystudio107 9 | # @copyright Copyright (c) 2022 nystudio107 10 | # @link https://nystudio107.com/ 11 | # @license MIT 12 | 13 | # Ensure permissions on directories Craft needs to write to 14 | chown -R www-data:www-data /var/www/project/cms/storage 15 | chown -R www-data:www-data /var/www/project/cms/web/cpresources 16 | # Check for `composer.lock` & `vendor/autoload.php` 17 | cd /var/www/project/cms 18 | if [ ! -f "composer.lock" ] || [ ! -f "vendor/autoload.php" ]; then 19 | su-exec www-data composer install --verbose --no-progress --no-scripts --optimize-autoloader --no-interaction 20 | # Wait until the Postgres db container responds 21 | echo "### Waiting for Postgres database" 22 | until eval "PGPASSWORD=$DB_PASSWORD psql -h postgres -U $DB_USER $DB_DATABASE -c 'select 1' > /dev/null 2>&1" 23 | do 24 | sleep 1 25 | done 26 | # Run any pending migrations/project config changes 27 | su-exec www-data composer craft-update 28 | fi 29 | -------------------------------------------------------------------------------- /.docker-config/php-prod-craft/run_queue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Run Queue shell script 4 | # 5 | # This shell script runs the Craft CMS queue via `php craft queue/listen` 6 | # It waits until the database container responds, then runs any pending 7 | # migrations / project config changes via the `craft-update` Composer script, 8 | # then runs the queue listener that listens for and runs pending queue jobs 9 | # 10 | # @author nystudio107 11 | # @copyright Copyright (c) 2022 nystudio107 12 | # @link https://nystudio107.com/ 13 | # @license MIT 14 | 15 | cd /var/www/project/cms 16 | # Wait until the Postgres db container responds 17 | echo "### Waiting for Postgres database" 18 | until eval "PGPASSWORD=$DB_PASSWORD psql -h postgres -U $DB_USER $DB_DATABASE -c 'select 1' > /dev/null 2>&1" 19 | do 20 | sleep 1 21 | done 22 | # Wait until the `composer install` is done by looking for the `vendor/autoload.php` and `composer.lock` files 23 | echo "### Waiting for vendor/autoload.php" 24 | while [ ! -f "vendor/autoload.php" ] || [ ! -f "composer.lock" ] 25 | do 26 | sleep 1 27 | done 28 | # Ensure permissions on directories Craft needs to write to 29 | chown -R www-data:www-data /var/www/project/cms/storage 30 | chown -R www-data:www-data /var/www/project/cms/web/cpresources 31 | # Run any pending migrations/project config changes 32 | su-exec www-data composer craft-update 33 | # Run a queue listener 34 | su-exec www-data php craft queue/listen 10 35 | -------------------------------------------------------------------------------- /.docker-config/postgres/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:13-alpine 2 | -------------------------------------------------------------------------------- /.docker-config/redis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis:5-alpine 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.git 2 | **/.idea 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @khalwat 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) nystudio107. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Determine the docker compose API version to get the separator character 2 | VERSION?=$(shell docker-compose -v) 3 | ifneq (,$(findstring v2.,$(VERSION))) 4 | SEPARATOR:=- 5 | else 6 | SEPARATOR:=_ 7 | endif 8 | CONTAINER?=$(shell basename $(CURDIR))$(SEPARATOR)php$(SEPARATOR)1 9 | BUILDCHAIN?=$(shell basename $(CURDIR))$(SEPARATOR)vite$(SEPARATOR)1 10 | 11 | .PHONY: build clean composer craft dev npm pulldb restoredb nuke ssh up 12 | 13 | # Production build via the buildchain container 14 | build: up 15 | docker exec -it $(BUILDCHAIN) npm run build 16 | # Remove `vendor/`, `node_modules` & lockfiles 17 | clean: 18 | rm -f cms/composer.lock 19 | rm -rf cms/vendor/ 20 | rm -f buildchain/package-lock.json 21 | rm -rf buildchain/node_modules/ 22 | # Executed a composer command in the PHP container 23 | composer: up 24 | docker exec -it $(CONTAINER) su-exec www-data composer \ 25 | $(filter-out $@,$(MAKECMDGOALS)) $(MAKEFLAGS) 26 | # Executed a craft command in the PHP container 27 | craft: up 28 | docker exec -it $(CONTAINER) su-exec www-data php craft \ 29 | $(filter-out $@,$(MAKECMDGOALS)) $(MAKEFLAGS) 30 | # Start the dev server 31 | dev: up 32 | # Executed an npm command in the buildchain container 33 | npm: up 34 | docker exec -it $(BUILDCHAIN) npm \ 35 | $(filter-out $@,$(MAKECMDGOALS)) $(MAKEFLAGS) 36 | pulldb: up 37 | cd scripts/ && ./docker_pull_db.sh 38 | restoredb: up 39 | cd scripts/ && ./docker_restore_db.sh \ 40 | $(filter-out $@,$(MAKECMDGOALS)) $(MAKEFLAGS) 41 | # Remove the Docker volumes & start clean 42 | nuke: clean 43 | docker-compose down -v 44 | docker-compose up --build --force-recreate 45 | # Open up a shell in the PHP container 46 | ssh: 47 | docker exec -it $(CONTAINER) su-exec www-data /bin/sh 48 | up: 49 | if [ ! "$$(docker ps -q -f name=$(CONTAINER))" ]; then \ 50 | cp -n cms/example.env cms/.env; \ 51 | docker-compose up; \ 52 | fi 53 | %: 54 | @: 55 | # ref: https://stackoverflow.com/questions/6273608/how-to-pass-argument-to-makefile-from-command-line 56 | -------------------------------------------------------------------------------- /buildchain/eslint.config.js: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | import pluginJs from "@eslint/js"; 3 | import tseslint from "typescript-eslint"; 4 | import pluginVue from "eslint-plugin-vue"; 5 | 6 | 7 | /** @type {import('eslint').Linter.Config[]} */ 8 | export default [ 9 | {files: ["**/*.{js,mjs,cjs,ts,vue}"]}, 10 | {languageOptions: { globals: globals.browser }}, 11 | pluginJs.configs.recommended, 12 | ...tseslint.configs.recommended, 13 | ...pluginVue.configs["flat/essential"], 14 | {files: ["**/*.vue"], languageOptions: {parserOptions: {parser: tseslint.parser}}}, 15 | ]; -------------------------------------------------------------------------------- /buildchain/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devmode-fm", 3 | "description": "Website for the devMode.fm podcast", 4 | "type": "module", 5 | "version": "1.0.0", 6 | "author": { 7 | "email": "andrew@nystudio107.com", 8 | "name": "Andrew Welch", 9 | "url": "https://nystudio107.com" 10 | }, 11 | "keywords": [ 12 | "devmode", 13 | "podcast", 14 | "modern", 15 | "web", 16 | "development" 17 | ], 18 | "homepage": "https://devMode.fm", 19 | "bugs": { 20 | "email": "andrew@nystudio107.com", 21 | "url": "https://nystudio107.com" 22 | }, 23 | "license": "MIT", 24 | "private": true, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/nystudio107/devmode.git" 28 | }, 29 | "dependencies": { 30 | "axios": "^1.7.9", 31 | "lazysizes": "^5.2.2", 32 | "picturefill": "^3.0.2", 33 | "tiny-cookie": "^1.0.1", 34 | "vue": "^2.6.0", 35 | "vue-clickaway": "^2.1.0", 36 | "vue-events": "^3.1.0", 37 | "vue-snowf": "0.0.2", 38 | "vue-typer": "^1.2.0", 39 | "vuetable-2": "^1.7.5" 40 | }, 41 | "devDependencies": { 42 | "@builder.io/partytown": "^0.3.6", 43 | "@eslint/js": "^9.19.0", 44 | "@types/node": "^22.0.0", 45 | "@tailwindcss/vite": "^4.0.0", 46 | "@vitejs/plugin-legacy": "^6.0.0", 47 | "@vitejs/plugin-vue2": "^2.3.3", 48 | "eslint": "^9.19.0", 49 | "eslint-plugin-vue": "^9.0.0", 50 | "globals": "^15.0.0", 51 | "rollup-plugin-critical": "^1.0.12", 52 | "rollup-plugin-visualizer": "^5.0.0", 53 | "stylelint": "^16.0.0", 54 | "stylelint-config-recommended": "^15.0.0", 55 | "stylelint-config-recommended-vue": "^1.0.0", 56 | "stylelint-config-standard-scss": "^14.0.0", 57 | "tailwindcss": "^4.0.0", 58 | "typescript": "^5.0.0", 59 | "typescript-eslint": "^8.0.0", 60 | "vite": "^6.0.0", 61 | "vite-plugin-checker": "^0.8.0", 62 | "vite-plugin-compression": "^0.5.0", 63 | "vite-plugin-favicon2": "^1.1.3", 64 | "vite-plugin-manifest-sri": "^0.2.0", 65 | "vite-plugin-restart": "^0.4.0", 66 | "vue-tsc": "^2.0.0" 67 | }, 68 | "scripts": { 69 | "dev": "vite", 70 | "build": "vite build --debug" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /buildchain/src/css/app.css: -------------------------------------------------------------------------------- 1 | /** 2 | * This injects Tailwind's base styles, which is a combination of 3 | * Normalize.css and some additional base styles. 4 | */ 5 | @import "tailwindcss"; 6 | @import "./tailwind-config.css"; 7 | 8 | /** 9 | * Here we add custom component classes; stuff we want loaded 10 | * *before* the utilities so that the utilities can still 11 | * override them. 12 | */ 13 | @import "./components/global.css"; 14 | @import "./components/fontello-codes.css"; 15 | @import "./components/tables.css"; 16 | @import "./components/range-slider.css"; 17 | @import "./components/typography.css"; 18 | @import "./components/webfonts.css"; 19 | @import "./components/webmentions.css"; 20 | 21 | /** 22 | * Include styles for individual pages 23 | */ 24 | @import "./pages/homepage.css"; 25 | 26 | /** 27 | * Include vendor css. 28 | */ 29 | @import "./vendor.css"; 30 | -------------------------------------------------------------------------------- /buildchain/src/css/components/fontello-codes.css: -------------------------------------------------------------------------------- 1 | .icon-search::before { content: "\e800"; } /* '' */ 2 | .icon-twitter::before { content: "\e801"; } /* '' */ 3 | .icon-facebook::before { content: "\e802"; } /* '' */ 4 | .icon-mail-alt::before { content: "\e803"; } /* '' */ 5 | .icon-location::before { content: "\e804"; } /* '' */ 6 | .icon-left-open::before { content: "\e805"; } /* '' */ 7 | .icon-right-open::before { content: "\e806"; } /* '' */ 8 | .icon-youtube-play::before { content: "\e807"; } /* '' */ 9 | .icon-book-open::before { content: "\e808"; } /* '' */ 10 | .icon-attention-alt::before { content: "\e809"; } /* '' */ 11 | .icon-plus-circled::before { content: "\e80a"; } /* '' */ 12 | .icon-minus-circled::before { content: "\e80b"; } /* '' */ 13 | .icon-help-circled::before { content: "\e80c"; } /* '' */ 14 | .icon-info-circled::before { content: "\e80d"; } /* '' */ 15 | .icon-calendar::before { content: "\e80e"; } /* '' */ 16 | .icon-down-dir::before { content: "\e80f"; } /* '' */ 17 | .icon-star::before { content: "\e810"; } /* '' */ 18 | .icon-star-half-alt::before { content: "\e811"; } /* '' */ 19 | .icon-star-empty::before { content: "\e812"; } /* '' */ 20 | .icon-linkedin::before { content: "\e813"; } /* '' */ 21 | .icon-pinterest::before { content: "\e814"; } /* '' */ 22 | .icon-github-circled::before { content: "\e815"; } /* '' */ 23 | .icon-flash::before { content: "\e816"; } /* '' */ 24 | .icon-link::before { content: "\e817"; } /* '' */ 25 | .icon-note-beamed::before { content: "\e818"; } /* '' */ 26 | .icon-play::before { content: "\e819"; } /* '' */ 27 | .icon-pause::before { content: "\e81a"; } /* '' */ 28 | .icon-google-play::before { content: "\e81b"; } /* '' */ 29 | .icon-itunes::before { content: "\e81c"; } /* '' */ 30 | .icon-comment::before { content: "\e81d"; } /* '' */ 31 | .icon-rss::before { content: "\f09e"; } /* '' */ 32 | .icon-menu::before { content: "\f0c9"; } /* '' */ 33 | .icon-code::before { content: "\f121"; } /* '' */ 34 | .icon-mic::before { content: "\f130"; } /* '' */ 35 | .icon-plug::before { content: "\f1e6"; } /* '' */ 36 | -------------------------------------------------------------------------------- /buildchain/src/css/components/range-slider.css: -------------------------------------------------------------------------------- 1 | /* Input Range */ 2 | input[type=range] { 3 | -webkit-appearance: none; 4 | width: 100%; 5 | border-radius: 10px; 6 | height: 12px; 7 | background-image: linear-gradient(90deg, theme('colors.devmode-pink') 0%, theme('colors.devmode-yellow') 0%); 8 | cursor: pointer; 9 | } 10 | 11 | input[type="range"]::-moz-range-track { 12 | border: none; 13 | background: none; 14 | outline: none; 15 | } 16 | 17 | input[type="range"]::-ms-track { 18 | width: 100%; 19 | cursor: pointer; 20 | 21 | /* Hides the slider so custom styles can be added */ 22 | background: transparent; 23 | border-color: transparent; 24 | color: transparent; 25 | } 26 | 27 | input[type="range"]:focus { 28 | outline: none; 29 | border: none; 30 | box-shadow: 1px 1px 1px 0px rgba(25, 25, 25, 0.2); 31 | } 32 | 33 | input[type="range"]::-moz-focus-outer { 34 | outline: none; 35 | border: none; 36 | box-shadow: 1px 1px 1px 0px rgba(25, 25, 25, 0.2); 37 | } 38 | 39 | input[type="range"]::-webkit-slider-thumb { 40 | -webkit-appearance: none; 41 | background-color: theme('colors.devmode-pink'); 42 | height: 24px; 43 | width: 24px; 44 | border-radius: 50%; 45 | border: 0; 46 | cursor: pointer; 47 | } 48 | 49 | input[type="range"]::-moz-range-thumb { 50 | -moz-appearance: none; 51 | background-color: theme('colors.devmode-pink'); 52 | border: none; 53 | height: 24px; 54 | width: 24px; 55 | border-radius: 50%; 56 | border: 0; 57 | cursor: pointer; 58 | } 59 | 60 | input[type="range"]::-ms-thumb { 61 | -moz-appearance: none; 62 | background-color: theme('colors.devmode-pink'); 63 | border: none; 64 | height: 24px; 65 | width: 24px; 66 | border-radius: 50%; 67 | border: 0; 68 | cursor: pointer; 69 | } 70 | -------------------------------------------------------------------------------- /buildchain/src/css/components/tables.css: -------------------------------------------------------------------------------- 1 | /** 2 | * components/tables.css 3 | * 4 | * Project Tables. 5 | * 6 | */ 7 | 8 | /* stylelint-disable */ 9 | 10 | table.vuetable { 11 | width: 100%; 12 | padding: 0; 13 | } 14 | 15 | table.vuetable thead { 16 | display: none; 17 | } 18 | 19 | /** 20 | * Column alignment 21 | */ 22 | td.text-center { 23 | text-align: center; 24 | } 25 | 26 | td.text-right { 27 | text-align: right; 28 | } 29 | 30 | .vuetable-empty-result { 31 | color: white; 32 | } 33 | 34 | /** 35 | * Misc 36 | */ 37 | 38 | .btn { 39 | height: 32px; 40 | display: inline-block; 41 | border-radius: 250px; 42 | margin-right: 4px; 43 | color: #eb5286; 44 | padding: 6px 12px; 45 | border: none; 46 | text-align: center; 47 | vertical-align: baseline; 48 | white-space: nowrap; 49 | user-select: none; 50 | user-select: none; 51 | user-select: none; 52 | user-select: none; 53 | cursor: pointer; 54 | box-sizing: border-box; 55 | box-sizing: border-box; 56 | appearance: none; 57 | appearance: none; 58 | appearance: none; 59 | box-shadow: inset 0 0 0 1px transparent, 0 0 0 1px rgb(0 0 0 / 2.5%), 0 1px 1px rgb(0 0 0 / 10%); 60 | box-shadow: inset 0 0 0 1px transparent, 0 0 0 1px rgb(0 0 0 / 2.5%), 0 1px 1px rgb(0 0 0 / 10%); 61 | } 62 | 63 | .btn:hover { 64 | text-decoration: none; 65 | } 66 | 67 | .disabled { 68 | opacity: 0.25; 69 | } 70 | 71 | .disabled, 72 | .disabled .btn { 73 | cursor: default; 74 | } 75 | 76 | .btn:not(.submit) { 77 | color: #eb5286; 78 | background-image: none; 79 | } 80 | 81 | .btn:not(.submit):active, 82 | .btn:not(.submit).active { 83 | background-color: #f2d024; 84 | background-image: none; 85 | } 86 | -------------------------------------------------------------------------------- /buildchain/src/css/components/typography.css: -------------------------------------------------------------------------------- 1 | /** 2 | * components/typography.css 3 | * 4 | * Typography rules. 5 | * 6 | */ 7 | -------------------------------------------------------------------------------- /buildchain/src/css/components/webfonts.css: -------------------------------------------------------------------------------- 1 | /** 2 | * components/webfonts.css 3 | * 4 | * Project webfonts. 5 | * 6 | */ 7 | -------------------------------------------------------------------------------- /buildchain/src/css/components/webmentions.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable */ 2 | .webmentions { 3 | display: block; 4 | text-align: left; 5 | } 6 | 7 | .webmentions__facepile { 8 | display: flex; 9 | align-items: center; 10 | flex-wrap: wrap; 11 | margin-left: 8px; 12 | margin-bottom: 1em; 13 | } 14 | 15 | .webmentions__facepile > h3 { 16 | float: left; 17 | margin: 0 28px 0 -8px; 18 | } 19 | 20 | .webmentions__facepile__hedlg { 21 | min-width: 180px; 22 | } 23 | 24 | .webmentions__facepile > a { 25 | margin-left: -16px; 26 | width: 3rem; 27 | height: 3rem; 28 | border-radius: 50%; 29 | border: 4px solid #fff; 30 | line-height: 1; 31 | overflow: hidden; 32 | box-sizing: content-box; 33 | } 34 | 35 | .webmentions__facepile > a:hover { 36 | position: relative; 37 | z-index: 1; 38 | } 39 | 40 | @supports (object-fit: cover) { 41 | .webmentions__face { 42 | object-fit: cover; 43 | height: 100%; 44 | width: 100%; 45 | } 46 | } 47 | 48 | .webmentions__list { 49 | list-style-type: none; 50 | } 51 | 52 | .webmentions__list.webmentions__list.webmentions__list { 53 | padding: 0; 54 | } 55 | 56 | .webmentions__item { 57 | margin-bottom: 1em; 58 | } 59 | 60 | .form-webmention { 61 | margin-bottom: 2rem; 62 | } 63 | 64 | .form-webmention label { 65 | display: block; 66 | } 67 | 68 | .form-webmention input { 69 | height: 2rem; 70 | } 71 | 72 | .form-webmention input[type="url"] { 73 | width: calc(100% - 13em); 74 | max-width: 30em; 75 | } 76 | 77 | .form-webmention [type="submit"] { 78 | appearance: none; 79 | margin-left: 0.25em; 80 | width: 12em; 81 | } 82 | -------------------------------------------------------------------------------- /buildchain/src/css/pages/homepage.css: -------------------------------------------------------------------------------- 1 | /** 2 | * pages/homepage.pcss 3 | * 4 | * Styles for the Home page. 5 | * 6 | */ 7 | 8 | .menuBlock { 9 | display: block!important; 10 | } 11 | -------------------------------------------------------------------------------- /buildchain/src/css/tailwind-config.css: -------------------------------------------------------------------------------- 1 | /** 2 | * tailwind-config.css 3 | * 4 | * CSS-based configuration for Tailwind CSS 5 | * ref: https://tailwindcss.com/docs/theme 6 | */ 7 | 8 | @source "../../../cms/templates/"; 9 | @source "../.././node_modules/vuetable-2/src/components/"; 10 | 11 | @theme { 12 | --color-devmode-pink: #eb5286; 13 | --color-devmode-aqua: #00b2c2; 14 | --color-devmode-yellow: #f2d024; 15 | --text-xxs: 0.5rem; 16 | --text-huge: 5rem; 17 | --breakpoint-sm: 576px; 18 | --breakpoint-md: 768px; 19 | --breakpoint-lg: 992px; 20 | --breakpoint-xl: 1200px; 21 | } 22 | -------------------------------------------------------------------------------- /buildchain/src/css/vendor.css: -------------------------------------------------------------------------------- 1 | /** 2 | * vendor.css 3 | * 4 | * All vendor CSS is imported here. 5 | */ 6 | -------------------------------------------------------------------------------- /buildchain/src/fontello/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/fontello/.gitkeep -------------------------------------------------------------------------------- /buildchain/src/img/devmodefm-social-media.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/img/devmodefm-social-media.png -------------------------------------------------------------------------------- /buildchain/src/img/favicon-src.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/img/favicon-src.png -------------------------------------------------------------------------------- /buildchain/src/js/@types/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module "app"; 2 | declare module "vue-clickaway"; 3 | declare module "vue-typer"; 4 | declare module "vue-snowf"; 5 | declare module "lazysizes"; 6 | declare module "player"; 7 | declare module "episodes"; 8 | -------------------------------------------------------------------------------- /buildchain/src/js/app.ts: -------------------------------------------------------------------------------- 1 | import Snowf from 'vue-snowf'; 2 | import '@/css/app.css'; 3 | 4 | // App main 5 | const main = async () => { 6 | // Async load the vue module 7 | const {default: Vue} = await import(/* webpackChunkName: "vue" */ 'vue'); 8 | // Async load the vue module 9 | const {mixin: VueClickaway} = await import(/* webpackChunkName: "vueclickaway" */ 'vue-clickaway'); 10 | const {default: VueTyper} = await import(/* webpackChunkName: "vuetyper" */ 'vue-typer'); 11 | Vue.use(VueTyper); 12 | // Create our vue instance 13 | new Vue({ 14 | el: '#page-header', 15 | delimiters: ['${', '}'], 16 | components: { 17 | Snowf, 18 | }, 19 | mixins: [VueClickaway], 20 | data: () => ({ 21 | menuOpen: false, 22 | }), 23 | methods: { 24 | // Pre-render pages when the user mouses over a link 25 | // Usage: 26 | prerenderLink: function (e: Event) { 27 | const head = document.getElementsByTagName("head")[0]; 28 | const refs = head.childNodes; 29 | const ref = refs[refs.length - 1]; 30 | 31 | const elements = head.getElementsByTagName("link"); 32 | Array.prototype.forEach.call(elements, function (el) { 33 | if (("rel" in el) && (el.rel === "prerender")) { 34 | el.parentNode.removeChild(el); 35 | } 36 | }); 37 | 38 | if (ref.parentNode && e.currentTarget) { 39 | const target: HTMLAnchorElement = e.currentTarget; 40 | const prerenderTag = document.createElement("link"); 41 | prerenderTag.rel = "prerender"; 42 | prerenderTag.href = target.href; 43 | ref.parentNode.insertBefore(prerenderTag, ref); 44 | } 45 | }, 46 | away: function () { 47 | this.menuOpen = false; 48 | }, 49 | toggle: function () { 50 | this.menuOpen = !this.menuOpen; 51 | }, 52 | }, 53 | }); 54 | }; 55 | // Execute async function 56 | main().then(() => { 57 | console.log(); 58 | }); 59 | 60 | // Accept HMR as per: https://vitejs.dev/guide/api-hmr.html 61 | if (import.meta.hot) { 62 | import.meta.hot.accept(() => { 63 | console.log("HMR") 64 | }); 65 | } 66 | -------------------------------------------------------------------------------- /buildchain/src/js/modules/episodes.js: -------------------------------------------------------------------------------- 1 | import lazyLoadComponent from '@/js/utils/lazy-load-component'; 2 | import SkeletonBox from '@/vue/SkeletonBox.vue'; 3 | 4 | // App main 5 | const main = async () => { 6 | // Async load the vue module 7 | const {default: Vue} = await import(/* webpackChunkName: "vue" */ 'vue'); 8 | const {default: VueEvents} = await import(/* webpackChunkName: "vueevents" */ 'vue-events'); 9 | 10 | Vue.use(VueEvents); 11 | // Create our vue instance 12 | new Vue({ 13 | el: "#episodes-table", 14 | components: { 15 | 'episodes-table': lazyLoadComponent({ 16 | componentFactory: () => import(/* webpackChunkName: "episodestable" */ '@/vue/EpisodesTable.vue'), 17 | loading: SkeletonBox, 18 | loadingData: {height: `100vh`, width: `100%`}, 19 | }), 20 | }, 21 | data: function () { 22 | return {}; 23 | }, 24 | mounted() { 25 | this.$events.$on('refresh-table', eventData => this.onTableRefresh(eventData)); 26 | }, 27 | methods: { 28 | onTableRefresh(vuetable) { 29 | Vue.nextTick(() => vuetable.refresh()); 30 | } 31 | }, 32 | }); 33 | }; 34 | 35 | // Execute async function 36 | main().then(() => { 37 | console.log(); 38 | }); 39 | 40 | // Accept HMR as per: https://vitejs.dev/guide/api-hmr.html 41 | if (import.meta.hot) { 42 | import.meta.hot.accept(() => { 43 | console.log("HMR") 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /buildchain/src/js/modules/player.js: -------------------------------------------------------------------------------- 1 | // App main 2 | const main = async () => { 3 | // Async load the vue module 4 | const {default: Vue} = await import(/* webpackChunkName: "vue" */ 'vue'); 5 | // Create our vue instance 6 | new Vue({ 7 | el: "#devmode-player", 8 | components: { 9 | 'devmode-player': () => import(/* webpackChunkName: "devmodeplayer" */ '@/vue/DevmodePlayer.vue'), 10 | }, 11 | data: function () { 12 | return {}; 13 | }, 14 | }); 15 | }; 16 | 17 | // Execute async function 18 | main().then(() => { 19 | console.log(); 20 | }); 21 | 22 | // Accept HMR as per: https://vitejs.dev/guide/api-hmr.html 23 | if (import.meta.hot) { 24 | import.meta.hot.accept(() => { 25 | console.log("HMR") 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /buildchain/src/js/utils/lazy-load-component.js: -------------------------------------------------------------------------------- 1 | // from: https://markus.oberlehner.net/blog/lazy-load-vue-components-when-they-become-visible/ 2 | export default function lazyLoadComponent({ 3 | componentFactory, 4 | loading, 5 | loadingData, 6 | }) { 7 | let resolveComponent; 8 | 9 | return () => ({ 10 | // We return a promise to resolve a 11 | // component eventually. 12 | component: new Promise((resolve) => { 13 | resolveComponent = resolve; 14 | }), 15 | loading: { 16 | mounted() { 17 | // We immediately load the component if 18 | // `IntersectionObserver` is not supported. 19 | if (!('IntersectionObserver' in window)) { 20 | componentFactory().then(resolveComponent); 21 | return; 22 | } 23 | 24 | const observer = new IntersectionObserver((entries) => { 25 | // Use `intersectionRatio` because of Edge 15's 26 | // lack of support for `isIntersecting`. 27 | // See: https://github.com/w3c/IntersectionObserver/issues/211 28 | if (entries[0].intersectionRatio <= 0) return; 29 | 30 | // Cleanup the observer when it's not 31 | // needed anymore. 32 | observer.unobserve(this.$el); 33 | // The `componentFactory()` resolves 34 | // to the result of a dynamic `import()` 35 | // which is passed to the `resolveComponent()` 36 | // function. 37 | componentFactory().then(resolveComponent); 38 | }); 39 | // We observe the root `$el` of the 40 | // mounted loading component to detect 41 | // when it becomes visible. 42 | observer.observe(this.$el); 43 | }, 44 | // Here we render the the component passed 45 | // to this function via the `loading` parameter. 46 | render(createElement) { 47 | return createElement(loading, loadingData); 48 | }, 49 | }, 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /buildchain/src/js/utils/lazysizes-wrapper.ts: -------------------------------------------------------------------------------- 1 | // Load the lazysizes JS for legacy browsers 2 | // this small shim is used to allow tranpilation of the loading code 3 | const main = async() => { 4 | const LazySizes = await import(/* webpackChunkName: "lazysizes" */ 'lazysizes'); 5 | LazySizes.init(); 6 | }; 7 | // Execute async function 8 | main().then(() => { 9 | console.log(); 10 | }); 11 | -------------------------------------------------------------------------------- /buildchain/src/public/fonts/OperatorMonoSSm-Book.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/OperatorMonoSSm-Book.eot -------------------------------------------------------------------------------- /buildchain/src/public/fonts/OperatorMonoSSm-Book.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/OperatorMonoSSm-Book.ttf -------------------------------------------------------------------------------- /buildchain/src/public/fonts/OperatorMonoSSm-Book.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/OperatorMonoSSm-Book.woff -------------------------------------------------------------------------------- /buildchain/src/public/fonts/OperatorMonoSSm-Book.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/OperatorMonoSSm-Book.woff2 -------------------------------------------------------------------------------- /buildchain/src/public/fonts/OperatorMonoSSm-BookItalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/OperatorMonoSSm-BookItalic.eot -------------------------------------------------------------------------------- /buildchain/src/public/fonts/OperatorMonoSSm-BookItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/OperatorMonoSSm-BookItalic.ttf -------------------------------------------------------------------------------- /buildchain/src/public/fonts/OperatorMonoSSm-BookItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/OperatorMonoSSm-BookItalic.woff -------------------------------------------------------------------------------- /buildchain/src/public/fonts/OperatorMonoSSm-BookItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/OperatorMonoSSm-BookItalic.woff2 -------------------------------------------------------------------------------- /buildchain/src/public/fonts/fontello.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/fontello.eot -------------------------------------------------------------------------------- /buildchain/src/public/fonts/fontello.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/fontello.ttf -------------------------------------------------------------------------------- /buildchain/src/public/fonts/fontello.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/fontello.woff -------------------------------------------------------------------------------- /buildchain/src/public/fonts/fontello.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/buildchain/src/public/fonts/fontello.woff2 -------------------------------------------------------------------------------- /buildchain/src/vue/@types/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | -------------------------------------------------------------------------------- /buildchain/src/vue/EpisodeCell.vue: -------------------------------------------------------------------------------- 1 | 24 | 51 | -------------------------------------------------------------------------------- /buildchain/src/vue/EpisodesFieldDefs.js: -------------------------------------------------------------------------------- 1 | // Field definitions for EpisodesTable.vue 2 | export default [ 3 | { 4 | name: '__slot:episode-display', 5 | sortField: 'title', 6 | title: 'Episode', 7 | titleClass: 'center pageListingDisplay', 8 | dataClass: 'center', 9 | width: '100%', 10 | }, 11 | { 12 | name: 'summary', 13 | visible: false, 14 | }, 15 | { 16 | name: 'episodeNumber', 17 | visible: false, 18 | }, 19 | { 20 | name: 'postDate', 21 | visible: false, 22 | }, 23 | ]; 24 | -------------------------------------------------------------------------------- /buildchain/src/vue/PlayerSkeletonBox.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | 37 | 64 | -------------------------------------------------------------------------------- /buildchain/src/vue/SkeletonBox.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 36 | 37 | 71 | -------------------------------------------------------------------------------- /buildchain/src/vue/VuetableFilterBar.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 41 | -------------------------------------------------------------------------------- /buildchain/src/vue/VuetablePagination.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 78 | -------------------------------------------------------------------------------- /buildchain/src/vue/VuetablePaginationInfo.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | -------------------------------------------------------------------------------- /buildchain/src/vue/VuetablePaginationInfoMixin.vue: -------------------------------------------------------------------------------- 1 | 52 | -------------------------------------------------------------------------------- /buildchain/stylelint.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('stylelint').Config} */ 2 | export default { 3 | "extends": [ 4 | "stylelint-config-recommended", 5 | "stylelint-config-standard-scss" 6 | ], 7 | "rules": { 8 | "scss/at-rule-no-unknown": [ 9 | true, 10 | { 11 | "ignoreAtRules": [ 12 | "theme", 13 | "source", 14 | "utility", 15 | "variant", 16 | "custom-variant", 17 | "apply", 18 | "reference", 19 | "config", 20 | "plugin", 21 | ] 22 | } 23 | ], 24 | "no-invalid-position-at-import-rule": null, 25 | "block-no-empty": null, 26 | "selector-id-pattern": null, 27 | "selector-class-pattern": null, 28 | "no-descending-specificity": null, 29 | "font-family-no-missing-generic-family-keyword": null 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /buildchain/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true, 5 | "baseUrl": "node_modules", 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "experimentalDecorators": true, 9 | "importHelpers": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "noEmit": true, 13 | "noImplicitAny": true, 14 | "outDir": "./dist", 15 | "paths": { 16 | "@/*": [ 17 | "./src/*" 18 | ] 19 | }, 20 | "resolveJsonModule": true, 21 | "skipLibCheck": true, 22 | "sourceMap": true, 23 | "strict": true, 24 | "strictBindCallApply": true, 25 | "strictFunctionTypes": true, 26 | "strictNullChecks": true, 27 | "target": "esnext", 28 | "types": ["vite/client"], 29 | }, 30 | "include": [ 31 | "./src/**/*.ts", 32 | "./src/**/*.vue" 33 | ], 34 | "exclude": [ 35 | "./node_modules" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /cms/bootstrap.php: -------------------------------------------------------------------------------- 1 | safeLoad(); 16 | } 17 | 18 | // Define additional PHP constants 19 | // (see https://craftcms.com/docs/3.x/config/#php-constants) 20 | define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production'); 21 | 22 | // Set license key via .env 23 | define('CRAFT_LICENSE_KEY', trim(getenv('LICENSE_KEY'), '"')); 24 | -------------------------------------------------------------------------------- /cms/config/app.console.php: -------------------------------------------------------------------------------- 1 | App::env('APP_ID') ?: 'CraftCMS', 24 | 'modules' => [ 25 | 'site-module' => [ 26 | 'class' => \modules\sitemodule\SiteModule::class, 27 | ], 28 | ], 29 | 'bootstrap' => ['site-module'], 30 | 'components' => [ 31 | 'cache' => [ 32 | 'class' => yii\redis\Cache::class, 33 | 'keyPrefix' => App::env('APP_ID') ?: 'CraftCMS', 34 | 'redis' => [ 35 | 'hostname' => App::env('REDIS_HOSTNAME'), 36 | 'port' => App::env('REDIS_PORT'), 37 | 'database' => App::env('REDIS_CRAFT_DB'), 38 | ], 39 | ], 40 | 'deprecator' => [ 41 | 'throwExceptions' => App::env('DEV_MODE'), 42 | ], 43 | 'queue' => [ 44 | 'class' => craft\queue\Queue::class, 45 | 'ttr' => 10 * 60, 46 | ], 47 | 'redis' => [ 48 | 'class' => yii\redis\Connection::class, 49 | 'hostname' => App::env('REDIS_HOSTNAME'), 50 | 'port' => App::env('REDIS_PORT'), 51 | 'database' => App::env('REDIS_DEFAULT_DB'), 52 | ], 53 | ], 54 | ]; 55 | -------------------------------------------------------------------------------- /cms/config/app.web.php: -------------------------------------------------------------------------------- 1 | [ 22 | 'session' => static function() { 23 | // Get the default component config 24 | $config = App::sessionConfig(); 25 | // Override the class to use Redis' session class and our config settings 26 | $config['class'] = yii\redis\Session::class; 27 | $config['keyPrefix'] = App::env('APP_ID') ?: 'CraftCMS'; 28 | $config['redis'] = [ 29 | 'hostname' => App::env('REDIS_HOSTNAME'), 30 | 'port' => App::env('REDIS_PORT'), 31 | 'database' => App::env('REDIS_DEFAULT_DB'), 32 | ]; 33 | // Instantiate and return it 34 | return Craft::createObject($config); 35 | }, 36 | ], 37 | ]; 38 | -------------------------------------------------------------------------------- /cms/config/custom.php: -------------------------------------------------------------------------------- 1 | config->{mycustomsetting}. 7 | * 8 | * @see https://craftcms.com/docs/4.x/upgrade.html#configuration 9 | */ 10 | 11 | return [ 12 | ]; 13 | -------------------------------------------------------------------------------- /cms/config/db.php: -------------------------------------------------------------------------------- 1 | dsn(App::env('DB_DSN') ?: null) 16 | ->user(App::env('DB_USER')) 17 | ->password(App::env('DB_PASSWORD')) 18 | ->schema(App::env('DB_SCHEMA')) 19 | ->tablePrefix(App::env('DB_TABLE_PREFIX')); 20 | -------------------------------------------------------------------------------- /cms/config/fastcgi-cache-bust.php: -------------------------------------------------------------------------------- 1 | App::env('FAST_CGI_CACHE_PATH'), 30 | ]; 31 | -------------------------------------------------------------------------------- /cms/config/general.php: -------------------------------------------------------------------------------- 1 | aliases([ 17 | '@assetsUrl' => App::env('ASSETS_URL'), 18 | '@cloudfrontUrl' => App::env('CLOUDFRONT_URL'), 19 | '@transcodedEpisodes' => 'https://d21kofsrtbjnsd.cloudfront.net/', 20 | '@ptGoogleAnalyticsProxy' => 'https://dbt8fhq6c1i4k.cloudfront.net/', 21 | '@web' => App::env('SITE_URL'), 22 | '@webroot' => App::env('WEB_ROOT_PATH'), 23 | ]) 24 | ->allowUpdates(App::env('ALLOW_UPDATES')) 25 | ->allowAdminChanges(App::env('ALLOW_ADMIN_CHANGES')) 26 | ->backupOnUpdate(App::env('BACKUP_ON_UPDATE')) 27 | ->devMode(App::env('DEV_MODE')) 28 | ->enableTemplateCaching(App::env('ENABLE_TEMPLATE_CACHING')) 29 | ->resourceBasePath(App::env('WEB_ROOT_PATH') . '/cpresources') 30 | ->runQueueAutomatically(App::env('RUN_QUEUE_AUTOMATICALLY')) 31 | ->securityKey(App::env('SECURITY_KEY')) 32 | // Craft config settings from constants 33 | ->cacheDuration(false) 34 | ->defaultSearchTermOptions([ 35 | 'subLeft' => true, 36 | 'subRight' => true, 37 | ]) 38 | ->defaultTokenDuration('P2W') 39 | ->enableCsrfProtection(true) 40 | ->errorTemplatePrefix('errors/') 41 | ->extraFileKinds([ 42 | 'text' => [ 43 | 'extensions' => ['csv'], 44 | ], 45 | ]) 46 | ->generateTransformsBeforePageLoad(true) 47 | ->maxCachedCloudImageSize(3000) 48 | ->maxUploadFileSize('100M') 49 | ->omitScriptNameInUrls(true) 50 | ->useEmailAsUsername(true) 51 | ->usePathInfo(true); 52 | -------------------------------------------------------------------------------- /cms/config/project/addresses/fieldLayouts/81eddbf6-097d-49f3-8bf9-6ed21bb8bcac.yaml: -------------------------------------------------------------------------------- 1 | tabs: 2 | - 3 | elementCondition: null 4 | elements: 5 | - 6 | autocapitalize: true 7 | autocomplete: false 8 | autocorrect: true 9 | class: null 10 | dateAdded: '2025-02-02T14:30:36-05:00' 11 | disabled: false 12 | elementCondition: null 13 | id: null 14 | includeInCards: false 15 | inputType: null 16 | instructions: null 17 | label: null 18 | max: null 19 | min: null 20 | name: null 21 | orientation: null 22 | placeholder: null 23 | providesThumbs: false 24 | readonly: false 25 | requirable: false 26 | size: null 27 | step: null 28 | tip: null 29 | title: null 30 | type: craft\fieldlayoutelements\addresses\LabelField 31 | uid: 66fb27f9-32e9-4f40-841d-ce7016affc2e 32 | userCondition: null 33 | warning: null 34 | width: 100 35 | - 36 | attribute: countryCode 37 | dateAdded: '2025-02-02T14:30:36-05:00' 38 | elementCondition: null 39 | id: null 40 | includeInCards: false 41 | instructions: null 42 | label: null 43 | orientation: null 44 | providesThumbs: false 45 | requirable: false 46 | tip: null 47 | type: craft\fieldlayoutelements\addresses\CountryCodeField 48 | uid: 602dff09-3990-47e0-8945-5e0f9961718a 49 | userCondition: null 50 | warning: null 51 | width: 100 52 | - 53 | dateAdded: '2025-02-02T14:30:36-05:00' 54 | elementCondition: null 55 | includeInCards: true 56 | instructions: null 57 | label: null 58 | providesThumbs: false 59 | required: false 60 | tip: null 61 | type: craft\fieldlayoutelements\addresses\AddressField 62 | uid: a3783dcc-d342-4768-ba88-f3045580a743 63 | userCondition: null 64 | warning: null 65 | name: Content 66 | uid: 0d6d4523-a757-4db0-aaa4-afc4bfe058a9 67 | userCondition: null 68 | -------------------------------------------------------------------------------- /cms/config/project/entryTypes/about--cc4ea2bd-3bde-4bad-8f72-272fcc3c2a19.yaml: -------------------------------------------------------------------------------- 1 | color: null 2 | fieldLayouts: 3 | 3e41c36a-b6fb-45a8-bef5-a95b1cb9104b: 4 | tabs: 5 | - 6 | elementCondition: null 7 | elements: 8 | - 9 | autocapitalize: true 10 | autocomplete: false 11 | autocorrect: true 12 | class: null 13 | dateAdded: '2025-02-02T04:38:03+00:00' 14 | disabled: false 15 | elementCondition: null 16 | id: null 17 | includeInCards: false 18 | inputType: null 19 | instructions: null 20 | label: Title 21 | max: null 22 | min: null 23 | name: null 24 | orientation: null 25 | placeholder: null 26 | providesThumbs: false 27 | readonly: false 28 | required: true 29 | size: null 30 | step: null 31 | tip: null 32 | title: null 33 | type: craft\fieldlayoutelements\entries\EntryTitleField 34 | uid: fcef76fb-5665-4835-a1b3-6b202de3b3a2 35 | userCondition: null 36 | warning: null 37 | width: 100 38 | - 39 | dateAdded: '2025-02-02T04:38:03+00:00' 40 | elementCondition: null 41 | fieldUid: b5eb01ec-a6ed-4a08-9438-64e7138b08f0 # FAQs 42 | handle: null 43 | includeInCards: false 44 | instructions: null 45 | label: null 46 | providesThumbs: false 47 | required: false 48 | tip: null 49 | type: craft\fieldlayoutelements\CustomField 50 | uid: b8abb118-99e0-4dca-beb0-8ae5c731a71b 51 | userCondition: null 52 | warning: null 53 | width: 100 54 | name: About 55 | uid: a92f475d-6dda-4c1b-9958-ccc93e4f0aa6 56 | userCondition: null 57 | handle: about 58 | hasTitleField: true 59 | icon: null 60 | name: About 61 | showSlugField: true 62 | showStatusField: true 63 | slugTranslationKeyFormat: null 64 | slugTranslationMethod: site 65 | titleFormat: null 66 | titleTranslationKeyFormat: null 67 | titleTranslationMethod: '' 68 | -------------------------------------------------------------------------------- /cms/config/project/entryTypes/calendar--7f6ad724-41b7-4a93-bef9-7de87d1bb23e.yaml: -------------------------------------------------------------------------------- 1 | color: null 2 | fieldLayouts: 3 | 9edff6e0-a6a2-48af-bf47-46bcf0704960: 4 | tabs: 5 | - 6 | elementCondition: null 7 | elements: 8 | - 9 | autocapitalize: true 10 | autocomplete: false 11 | autocorrect: true 12 | class: null 13 | dateAdded: '2025-02-02T04:38:03+00:00' 14 | disabled: false 15 | elementCondition: null 16 | id: null 17 | includeInCards: false 18 | inputType: null 19 | instructions: null 20 | label: null 21 | max: null 22 | min: null 23 | name: null 24 | orientation: null 25 | placeholder: null 26 | providesThumbs: false 27 | readonly: false 28 | required: true 29 | size: null 30 | step: null 31 | tip: null 32 | title: null 33 | type: craft\fieldlayoutelements\entries\EntryTitleField 34 | uid: c069761f-2823-4657-b2b2-ce0b7e896bbd 35 | userCondition: null 36 | warning: null 37 | width: 100 38 | name: Content 39 | uid: f1c94c2b-be68-49aa-9a41-278431d971e8 40 | userCondition: null 41 | handle: calendar 42 | hasTitleField: true 43 | icon: null 44 | name: Calendar 45 | showSlugField: true 46 | showStatusField: true 47 | slugTranslationKeyFormat: null 48 | slugTranslationMethod: site 49 | titleFormat: '{section.name|raw}' 50 | titleTranslationKeyFormat: null 51 | titleTranslationMethod: '' 52 | -------------------------------------------------------------------------------- /cms/config/project/entryTypes/episodesIndex--50012289-791c-48b2-8df1-31a8f5eb5380.yaml: -------------------------------------------------------------------------------- 1 | color: null 2 | fieldLayouts: 3 | 871fe128-2837-48cb-a9ac-29f46ae27488: 4 | tabs: 5 | - 6 | elementCondition: null 7 | elements: 8 | - 9 | autocapitalize: true 10 | autocomplete: false 11 | autocorrect: true 12 | class: null 13 | dateAdded: '2025-02-02T04:38:03+00:00' 14 | disabled: false 15 | elementCondition: null 16 | id: null 17 | includeInCards: false 18 | inputType: null 19 | instructions: null 20 | label: null 21 | max: null 22 | min: null 23 | name: null 24 | orientation: null 25 | placeholder: null 26 | providesThumbs: false 27 | readonly: false 28 | required: true 29 | size: null 30 | step: null 31 | tip: null 32 | title: null 33 | type: craft\fieldlayoutelements\entries\EntryTitleField 34 | uid: d57f6696-fe10-4cb3-936d-4619d794c531 35 | userCondition: null 36 | warning: null 37 | width: 100 38 | name: Content 39 | uid: 90f85740-1500-4535-94f5-e7e3507dbf38 40 | userCondition: null 41 | handle: episodesIndex 42 | hasTitleField: false 43 | icon: null 44 | name: 'Episodes Index' 45 | showSlugField: true 46 | showStatusField: true 47 | slugTranslationKeyFormat: null 48 | slugTranslationMethod: site 49 | titleFormat: '{section.name|raw}' 50 | titleTranslationKeyFormat: null 51 | titleTranslationMethod: '' 52 | -------------------------------------------------------------------------------- /cms/config/project/entryTypes/faqs--a009e969-e0ed-429e-9ab3-98561af05518.yaml: -------------------------------------------------------------------------------- 1 | color: null 2 | fieldLayouts: 3 | 529896ec-dad3-4d01-8366-e2c4f7b33144: 4 | tabs: 5 | - 6 | elementCondition: null 7 | elements: 8 | - 9 | dateAdded: '2025-02-02T04:38:03+00:00' 10 | elementCondition: null 11 | fieldUid: e0264ea5-7834-42de-9f8f-c611149453d0 # FAQs - FAQs - Question 12 | handle: null 13 | includeInCards: true 14 | instructions: null 15 | label: Question 16 | providesThumbs: false 17 | required: false 18 | tip: null 19 | type: craft\fieldlayoutelements\CustomField 20 | uid: 53b49b35-e7bc-4e11-95fb-038ec716cf25 21 | userCondition: null 22 | warning: null 23 | width: 100 24 | - 25 | dateAdded: '2025-02-02T04:38:03+00:00' 26 | elementCondition: null 27 | fieldUid: 2bb6f342-1735-446e-b9fe-754f94dac82f # FAQs - FAQs - Answer 28 | handle: null 29 | includeInCards: false 30 | instructions: null 31 | label: Answer 32 | providesThumbs: false 33 | required: false 34 | tip: null 35 | type: craft\fieldlayoutelements\CustomField 36 | uid: ea93a09f-e0e0-4dcb-8d31-f466b6e1c60a 37 | userCondition: null 38 | warning: null 39 | width: 100 40 | - 41 | dateAdded: '2025-02-02T04:38:03+00:00' 42 | elementCondition: null 43 | fieldUid: 98dbc824-8c89-4138-9b0f-011a96875a7a # FAQs - FAQs - Links 44 | handle: null 45 | includeInCards: false 46 | instructions: null 47 | label: Links 48 | providesThumbs: false 49 | required: false 50 | tip: null 51 | type: craft\fieldlayoutelements\CustomField 52 | uid: 2d0d1694-aec7-4e93-beac-26460e8770c2 53 | userCondition: null 54 | warning: null 55 | width: 100 56 | name: Content 57 | uid: 3719d24a-d689-4ef9-b20a-252e6b3a6984 58 | userCondition: null 59 | handle: faqs 60 | hasTitleField: false 61 | icon: null 62 | name: FAQs 63 | showSlugField: false 64 | showStatusField: true 65 | slugTranslationKeyFormat: null 66 | slugTranslationMethod: site 67 | titleFormat: null 68 | titleTranslationKeyFormat: null 69 | titleTranslationMethod: site 70 | -------------------------------------------------------------------------------- /cms/config/project/entryTypes/homepage--9aae2c4b-7316-4ee9-a2d1-41474766b361.yaml: -------------------------------------------------------------------------------- 1 | color: null 2 | fieldLayouts: 3 | ebe72b6a-1b0b-4604-a42f-ab345572841c: 4 | tabs: 5 | - 6 | elementCondition: null 7 | elements: 8 | - 9 | autocapitalize: true 10 | autocomplete: false 11 | autocorrect: true 12 | class: null 13 | dateAdded: '2025-02-02T04:38:03+00:00' 14 | disabled: false 15 | elementCondition: null 16 | id: null 17 | includeInCards: false 18 | inputType: null 19 | instructions: null 20 | label: null 21 | max: null 22 | min: null 23 | name: null 24 | orientation: null 25 | placeholder: null 26 | providesThumbs: false 27 | readonly: false 28 | required: true 29 | size: null 30 | step: null 31 | tip: null 32 | title: null 33 | type: craft\fieldlayoutelements\entries\EntryTitleField 34 | uid: f62afa21-eaec-42c2-a60e-20b676a9d745 35 | userCondition: null 36 | warning: null 37 | width: 100 38 | name: Content 39 | uid: 7a8eae79-e971-4027-a389-2d32b24694e9 40 | userCondition: null 41 | handle: homepage 42 | hasTitleField: true 43 | icon: null 44 | name: Homepage 45 | showSlugField: true 46 | showStatusField: true 47 | slugTranslationKeyFormat: null 48 | slugTranslationMethod: site 49 | titleFormat: null 50 | titleTranslationKeyFormat: null 51 | titleTranslationMethod: '' 52 | -------------------------------------------------------------------------------- /cms/config/project/fields/answer--2bb6f342-1735-446e-b9fe-754f94dac82f.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: answer 3 | instructions: null 4 | name: 'FAQs - FAQs - Answer' 5 | searchable: true 6 | settings: 7 | errorMessage: 'Unable to find component class ''craft\redactor\Field''.' 8 | expectedType: craft\redactor\Field 9 | settings: 10 | __assoc__: 11 | - 12 | - availableTransforms 13 | - '*' 14 | - 15 | - availableVolumes 16 | - '*' 17 | - 18 | - cleanupHtml 19 | - true 20 | - 21 | - columnType 22 | - text 23 | - 24 | - purifierConfig 25 | - '' 26 | - 27 | - purifyHtml 28 | - '1' 29 | - 30 | - redactorConfig 31 | - Standard.json 32 | - 33 | - removeEmptyTags 34 | - '1' 35 | - 36 | - removeInlineStyles 37 | - '1' 38 | - 39 | - removeNbsp 40 | - '1' 41 | translationKeyFormat: null 42 | translationMethod: none 43 | type: craft\fields\MissingField 44 | -------------------------------------------------------------------------------- /cms/config/project/fields/episodeGuests--7e338b73-ac10-44cf-892e-04afc0164991.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: episodeGuests 3 | instructions: null 4 | name: 'Episode Guests' 5 | searchable: true 6 | settings: 7 | allowSelfRelations: false 8 | branchLimit: null 9 | maintainHierarchy: false 10 | maxRelations: null 11 | minRelations: null 12 | selectionLabel: null 13 | showCardsInGrid: false 14 | showSiteMenu: true 15 | sources: 16 | - 'section:214e4dc6-a454-4df0-a1f5-cd94ecdab53f' # Guests 17 | targetSiteId: null 18 | validateRelatedElements: false 19 | viewMode: null 20 | translationKeyFormat: null 21 | translationMethod: none 22 | type: craft\fields\Entries 23 | -------------------------------------------------------------------------------- /cms/config/project/fields/episodeHosts--a5cf9c0d-1797-4a60-8c47-bc28c5f01a95.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: episodeHosts 3 | instructions: null 4 | name: 'Episode Hosts' 5 | searchable: true 6 | settings: 7 | allowSelfRelations: false 8 | branchLimit: null 9 | maintainHierarchy: false 10 | maxRelations: null 11 | minRelations: null 12 | selectionLabel: null 13 | showCardsInGrid: false 14 | showSiteMenu: true 15 | sources: '*' 16 | targetSiteId: null 17 | validateRelatedElements: false 18 | viewMode: null 19 | translationKeyFormat: null 20 | translationMethod: none 21 | type: craft\fields\Users 22 | -------------------------------------------------------------------------------- /cms/config/project/fields/episodeMedia--0090f7a3-1e22-4fb5-9ae0-01de38805601.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: episodeMedia 3 | instructions: null 4 | name: 'Episode Media' 5 | searchable: true 6 | settings: 7 | allowSelfRelations: false 8 | allowSubfolders: false 9 | allowUploads: true 10 | allowedKinds: 11 | - audio 12 | branchLimit: null 13 | defaultUploadLocationSource: 'volume:e69c8edb-d562-4367-9a05-91a6fd2c7d99' # Devmode Episodes 14 | defaultUploadLocationSubpath: null 15 | maintainHierarchy: false 16 | maxRelations: 1 17 | minRelations: null 18 | previewMode: full 19 | restrictFiles: true 20 | restrictLocation: false 21 | restrictedDefaultUploadSubpath: null 22 | restrictedLocationSource: 'volume:e69c8edb-d562-4367-9a05-91a6fd2c7d99' # Devmode Episodes 23 | restrictedLocationSubpath: null 24 | selectionLabel: null 25 | showCardsInGrid: false 26 | showSiteMenu: true 27 | showUnpermittedFiles: false 28 | showUnpermittedVolumes: true 29 | sources: '*' 30 | targetSiteId: null 31 | validateRelatedElements: false 32 | viewMode: list 33 | translationKeyFormat: null 34 | translationMethod: none 35 | type: craft\fields\Assets 36 | -------------------------------------------------------------------------------- /cms/config/project/fields/episodeNumber--324e7a11-3346-41e7-a29d-4636ab907e51.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: episodeNumber 3 | instructions: null 4 | name: 'Episode Number' 5 | searchable: true 6 | settings: 7 | decimals: 0 8 | defaultValue: null 9 | max: null 10 | min: 1 11 | prefix: null 12 | previewCurrency: null 13 | previewFormat: decimal 14 | size: 10 15 | step: null 16 | suffix: null 17 | translationKeyFormat: null 18 | translationMethod: none 19 | type: craft\fields\Number 20 | -------------------------------------------------------------------------------- /cms/config/project/fields/episodeReferenceLinks--8c9dd611-b43b-4e22-b076-3f6a6362c93e.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: episodeReferenceLinks 3 | instructions: null 4 | name: 'Episode Reference Links' 5 | searchable: true 6 | settings: 7 | addRowLabel: 'Add a row' 8 | columns: 9 | __assoc__: 10 | - 11 | - col1 12 | - 13 | __assoc__: 14 | - 15 | - heading 16 | - 'Link Name' 17 | - 18 | - handle 19 | - linkName 20 | - 21 | - width 22 | - '' 23 | - 24 | - type 25 | - singleline 26 | - 27 | - col2 28 | - 29 | __assoc__: 30 | - 31 | - heading 32 | - 'Link URL' 33 | - 34 | - handle 35 | - linkUrl 36 | - 37 | - width 38 | - '' 39 | - 40 | - type 41 | - singleline 42 | maxRows: null 43 | minRows: null 44 | staticRows: false 45 | translationKeyFormat: null 46 | translationMethod: none 47 | type: craft\fields\Table 48 | -------------------------------------------------------------------------------- /cms/config/project/fields/episodeSummary--8011817c-9518-4a31-9aa8-cad6d4a08b81.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: episodeSummary 3 | instructions: null 4 | name: 'Episode Summary' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 6 11 | multiline: true 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/episodeTags--61953a92-8b34-4678-9bae-fd5a45142f26.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: episodeTags 3 | instructions: null 4 | name: 'Episode Tags' 5 | searchable: true 6 | settings: 7 | allowSelfRelations: false 8 | branchLimit: null 9 | maintainHierarchy: false 10 | maxRelations: null 11 | minRelations: null 12 | selectionLabel: null 13 | showCardsInGrid: false 14 | showSiteMenu: true 15 | source: 'taggroup:fc24a736-c435-4d8a-aeb3-6105afce1d91' # Episodes 16 | targetSiteId: null 17 | validateRelatedElements: false 18 | viewMode: null 19 | translationKeyFormat: null 20 | translationMethod: none 21 | type: craft\fields\Tags 22 | -------------------------------------------------------------------------------- /cms/config/project/fields/episodeTranscript--523395ea-5738-4ca5-a119-f32221ea5ca8.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: episodeTranscript 3 | instructions: 'CSV format transcript of the episode, with tabs as the field delimeter' 4 | name: 'Episode Transcript' 5 | searchable: false 6 | settings: 7 | allowSelfRelations: false 8 | allowSubfolders: false 9 | allowUploads: true 10 | allowedKinds: 11 | - text 12 | branchLimit: null 13 | defaultUploadLocationSource: 'volume:e69c8edb-d562-4367-9a05-91a6fd2c7d99' # Devmode Episodes 14 | defaultUploadLocationSubpath: null 15 | maintainHierarchy: false 16 | maxRelations: 1 17 | minRelations: null 18 | previewMode: full 19 | restrictFiles: true 20 | restrictLocation: false 21 | restrictedDefaultUploadSubpath: null 22 | restrictedLocationSource: 'volume:e69c8edb-d562-4367-9a05-91a6fd2c7d99' # Devmode Episodes 23 | restrictedLocationSubpath: null 24 | selectionLabel: 'Choose a CSV Transcript' 25 | showCardsInGrid: false 26 | showSiteMenu: false 27 | showUnpermittedFiles: false 28 | showUnpermittedVolumes: false 29 | sources: 30 | - 'volume:bd8ef0d7-f73b-4138-ac52-c14d11dd780e' # Devmode Transcripts 31 | targetSiteId: null 32 | validateRelatedElements: false 33 | viewMode: list 34 | translationKeyFormat: null 35 | translationMethod: none 36 | type: craft\fields\Assets 37 | -------------------------------------------------------------------------------- /cms/config/project/fields/errorHeadline--18d7721b-780b-4a44-976a-716c3df0bb7a.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: errorHeadline 3 | instructions: null 4 | name: 'Error Headline' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: false 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/errorImage--4d90d0e7-b705-4035-b396-2f82ce5bb871.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: errorImage 3 | instructions: null 4 | name: 'Error Image' 5 | searchable: true 6 | settings: 7 | allowSelfRelations: false 8 | allowSubfolders: false 9 | allowUploads: true 10 | allowedKinds: 11 | - image 12 | branchLimit: null 13 | defaultUploadLocationSource: 'volume:cd231c31-8caf-4b13-995d-2b84f9750c63' 14 | defaultUploadLocationSubpath: null 15 | maintainHierarchy: false 16 | maxRelations: 1 17 | minRelations: null 18 | previewMode: full 19 | restrictFiles: true 20 | restrictLocation: false 21 | restrictedDefaultUploadSubpath: null 22 | restrictedLocationSource: 'volume:cd231c31-8caf-4b13-995d-2b84f9750c63' 23 | restrictedLocationSubpath: null 24 | selectionLabel: null 25 | showCardsInGrid: false 26 | showSiteMenu: true 27 | showUnpermittedFiles: false 28 | showUnpermittedVolumes: true 29 | sources: 30 | - 'volume:7540db37-7ec3-4471-9de6-36bde06e949a' # Devmode Site 31 | targetSiteId: null 32 | validateRelatedElements: false 33 | viewMode: large 34 | translationKeyFormat: null 35 | translationMethod: none 36 | type: craft\fields\Assets 37 | -------------------------------------------------------------------------------- /cms/config/project/fields/errorText--e1087165-5769-428d-bf14-c98e6011cf5e.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: errorText 3 | instructions: null 4 | name: 'Error Text' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: true 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/faqs--b5eb01ec-a6ed-4a08-9438-64e7138b08f0.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: faqs 3 | instructions: null 4 | name: FAQs 5 | searchable: true 6 | settings: 7 | createButtonLabel: null 8 | defaultIndexViewMode: cards 9 | entryTypes: 10 | - 11 | __assoc__: 12 | - 13 | - uid 14 | - a009e969-e0ed-429e-9ab3-98561af05518 # FAQs 15 | includeTableView: false 16 | maxEntries: null 17 | minEntries: null 18 | pageSize: null 19 | propagationKeyFormat: null 20 | propagationMethod: all 21 | showCardsInGrid: false 22 | viewMode: blocks 23 | translationKeyFormat: null 24 | translationMethod: site 25 | type: craft\fields\Matrix 26 | -------------------------------------------------------------------------------- /cms/config/project/fields/links--98dbc824-8c89-4138-9b0f-011a96875a7a.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: links 3 | instructions: null 4 | name: 'FAQs - FAQs - Links' 5 | searchable: true 6 | settings: 7 | addRowLabel: 'Add a row' 8 | columns: 9 | __assoc__: 10 | - 11 | - col1 12 | - 13 | __assoc__: 14 | - 15 | - heading 16 | - 'Link Text' 17 | - 18 | - handle 19 | - linkText 20 | - 21 | - width 22 | - '' 23 | - 24 | - type 25 | - singleline 26 | - 27 | - col2 28 | - 29 | __assoc__: 30 | - 31 | - heading 32 | - 'Link Url' 33 | - 34 | - handle 35 | - linkUrl 36 | - 37 | - width 38 | - '' 39 | - 40 | - type 41 | - singleline 42 | maxRows: null 43 | minRows: null 44 | staticRows: false 45 | translationKeyFormat: null 46 | translationMethod: none 47 | type: craft\fields\Table 48 | -------------------------------------------------------------------------------- /cms/config/project/fields/optimizedImages--1be1c156-82fa-4f08-bb63-6d3417da2844.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: optimizedImages 3 | instructions: null 4 | name: 'Optimized Images' 5 | searchable: true 6 | settings: 7 | displayDominantColorPalette: true 8 | displayLazyLoadPlaceholderImages: true 9 | displayOptimizedImageVariants: true 10 | variants: 11 | - 12 | __assoc__: 13 | - 14 | - width 15 | - '1200' 16 | - 17 | - useAspectRatio 18 | - '1' 19 | - 20 | - aspectRatioX 21 | - '1' 22 | - 23 | - aspectRatioY 24 | - '1' 25 | - 26 | - retinaSizes 27 | - 28 | - '1' 29 | - 30 | - quality 31 | - '82' 32 | - 33 | - format 34 | - jpg 35 | - 36 | __assoc__: 37 | - 38 | - width 39 | - '992' 40 | - 41 | - useAspectRatio 42 | - '1' 43 | - 44 | - aspectRatioX 45 | - '1' 46 | - 47 | - aspectRatioY 48 | - '1' 49 | - 50 | - retinaSizes 51 | - 52 | - '1' 53 | - 54 | - quality 55 | - '82' 56 | - 57 | - format 58 | - jpg 59 | - 60 | __assoc__: 61 | - 62 | - width 63 | - '768' 64 | - 65 | - useAspectRatio 66 | - '1' 67 | - 68 | - aspectRatioX 69 | - '1' 70 | - 71 | - aspectRatioY 72 | - '1' 73 | - 74 | - retinaSizes 75 | - 76 | - '1' 77 | - 78 | - quality 79 | - '60' 80 | - 81 | - format 82 | - jpg 83 | - 84 | __assoc__: 85 | - 86 | - width 87 | - '576' 88 | - 89 | - useAspectRatio 90 | - '1' 91 | - 92 | - aspectRatioX 93 | - '1' 94 | - 95 | - aspectRatioY 96 | - '1' 97 | - 98 | - retinaSizes 99 | - 100 | - '1' 101 | - 102 | - quality 103 | - '60' 104 | - 105 | - format 106 | - jpg 107 | translationKeyFormat: null 108 | translationMethod: none 109 | type: nystudio107\imageoptimize\fields\OptimizedImages 110 | -------------------------------------------------------------------------------- /cms/config/project/fields/profileBio--9687721c-33b8-4a40-abb7-5c42e07ce274.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: profileBio 3 | instructions: null 4 | name: 'Profile Bio' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: true 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/profileCompany--c05161c0-a294-4d47-8909-1cfc88c2f970.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: profileCompany 3 | instructions: null 4 | name: 'Profile Company' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: false 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/profileGithubUrl--d6df6fe7-14f3-42a3-9949-dcee7c8c26d9.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: profileGithubUrl 3 | instructions: null 4 | name: 'Profile GitHub URL' 5 | searchable: true 6 | settings: 7 | fullGraphqlData: false 8 | maxLength: 255 9 | showLabelField: false 10 | types: 11 | - entry 12 | - url 13 | translationKeyFormat: null 14 | translationMethod: none 15 | type: craft\fields\Link 16 | -------------------------------------------------------------------------------- /cms/config/project/fields/profileOptimizedImages--41fdb4c8-4774-4101-918f-1412190b085b.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: profileOptimizedImages 3 | instructions: null 4 | name: 'Profile Optimized Images' 5 | searchable: true 6 | settings: 7 | displayDominantColorPalette: true 8 | displayLazyLoadPlaceholderImages: true 9 | displayOptimizedImageVariants: true 10 | variants: 11 | - 12 | __assoc__: 13 | - 14 | - width 15 | - '100' 16 | - 17 | - useAspectRatio 18 | - '1' 19 | - 20 | - aspectRatioX 21 | - '1' 22 | - 23 | - aspectRatioY 24 | - '1' 25 | - 26 | - retinaSizes 27 | - 28 | - '1' 29 | - '2' 30 | - 31 | - quality 32 | - '82' 33 | - 34 | - format 35 | - jpg 36 | translationKeyFormat: null 37 | translationMethod: none 38 | type: nystudio107\imageoptimize\fields\OptimizedImages 39 | -------------------------------------------------------------------------------- /cms/config/project/fields/profileTitle--380e3b7e-07de-4d39-b0e5-360f5e87d00d.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: profileTitle 3 | instructions: null 4 | name: 'Profile Title' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: false 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/profileTwitterUrl--406c20cb-9b86-4b0d-9123-1ce57220e2a8.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: profileTwitterUrl 3 | instructions: null 4 | name: 'Profile Twitter URL' 5 | searchable: true 6 | settings: 7 | fullGraphqlData: false 8 | maxLength: 255 9 | showLabelField: false 10 | types: 11 | - entry 12 | - url 13 | translationKeyFormat: null 14 | translationMethod: none 15 | type: craft\fields\Link 16 | -------------------------------------------------------------------------------- /cms/config/project/fields/profileUrl--31b8c511-37f9-4d83-956d-5aa215572122.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: profileUrl 3 | instructions: null 4 | name: 'Profile URL' 5 | searchable: true 6 | settings: 7 | fullGraphqlData: false 8 | maxLength: 255 9 | showLabelField: false 10 | types: 11 | - entry 12 | - url 13 | translationKeyFormat: null 14 | translationMethod: none 15 | type: craft\fields\Link 16 | -------------------------------------------------------------------------------- /cms/config/project/fields/question--e0264ea5-7834-42de-9f8f-c611149453d0.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: question 3 | instructions: null 4 | name: 'FAQs - FAQs - Question' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: false 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/relatedEpisodes--07f04bdf-277d-4010-9fbe-497cd9593324.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: relatedEpisodes 3 | instructions: null 4 | name: 'Related Episodes' 5 | searchable: false 6 | settings: 7 | allowSelfRelations: false 8 | branchLimit: null 9 | maintainHierarchy: false 10 | maxRelations: 3 11 | minRelations: null 12 | selectionLabel: null 13 | showCardsInGrid: false 14 | showSiteMenu: false 15 | sources: 16 | - 'section:c1f6af30-7375-4feb-92ef-a3ed16ba69b2' # Episodes 17 | targetSiteId: null 18 | validateRelatedElements: false 19 | viewMode: null 20 | translationKeyFormat: null 21 | translationMethod: none 22 | type: craft\fields\Entries 23 | -------------------------------------------------------------------------------- /cms/config/project/fields/showDescription--86909527-3ec4-4d57-a44c-167649eb86bf.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showDescription 3 | instructions: null 4 | name: 'Show Description' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 6 11 | multiline: true 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/showEmail--ca279869-925f-4960-865c-96cacd2aa942.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showEmail 3 | instructions: null 4 | name: 'Show Email' 5 | searchable: true 6 | settings: 7 | placeholder: null 8 | translationKeyFormat: null 9 | translationMethod: none 10 | type: craft\fields\Email 11 | -------------------------------------------------------------------------------- /cms/config/project/fields/showGenre--6def66f0-2a8f-4b88-9435-7f9cc1ccfe9c.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showGenre 3 | instructions: null 4 | name: 'Show Genre' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: false 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/showImage--bda219fa-bace-4d8b-ad3a-08243caaf6ca.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showImage 3 | instructions: null 4 | name: 'Show Image' 5 | searchable: true 6 | settings: 7 | allowSelfRelations: false 8 | allowSubfolders: false 9 | allowUploads: true 10 | allowedKinds: 11 | - image 12 | branchLimit: null 13 | defaultUploadLocationSource: 'volume:7540db37-7ec3-4471-9de6-36bde06e949a' # Devmode Site 14 | defaultUploadLocationSubpath: null 15 | maintainHierarchy: false 16 | maxRelations: 1 17 | minRelations: null 18 | previewMode: full 19 | restrictFiles: true 20 | restrictLocation: false 21 | restrictedDefaultUploadSubpath: null 22 | restrictedLocationSource: 'volume:e69c8edb-d562-4367-9a05-91a6fd2c7d99' # Devmode Episodes 23 | restrictedLocationSubpath: null 24 | selectionLabel: null 25 | showCardsInGrid: false 26 | showSiteMenu: true 27 | showUnpermittedFiles: false 28 | showUnpermittedVolumes: true 29 | sources: 30 | - 'volume:7540db37-7ec3-4471-9de6-36bde06e949a' # Devmode Site 31 | targetSiteId: null 32 | validateRelatedElements: false 33 | viewMode: large 34 | translationKeyFormat: null 35 | translationMethod: none 36 | type: craft\fields\Assets 37 | -------------------------------------------------------------------------------- /cms/config/project/fields/showItunesUrl--14605669-4768-4f57-88d6-1f06480a9b80.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showItunesUrl 3 | instructions: null 4 | name: 'Show iTunes URL' 5 | searchable: true 6 | settings: 7 | fullGraphqlData: false 8 | maxLength: 255 9 | showLabelField: false 10 | types: 11 | - entry 12 | - url 13 | translationKeyFormat: null 14 | translationMethod: none 15 | type: craft\fields\Link 16 | -------------------------------------------------------------------------------- /cms/config/project/fields/showRssFeedUrl--ab0ca0e9-1308-472f-92a5-2ab0cbd84943.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showRssFeedUrl 3 | instructions: null 4 | name: 'Show RSS Feed URL' 5 | searchable: true 6 | settings: 7 | fullGraphqlData: false 8 | maxLength: 255 9 | showLabelField: false 10 | types: 11 | - entry 12 | - url 13 | translationKeyFormat: null 14 | translationMethod: none 15 | type: craft\fields\Link 16 | -------------------------------------------------------------------------------- /cms/config/project/fields/showSubTitle--2405ed1c-fd52-4264-a96a-f6e6fab437b5.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showSubTitle 3 | instructions: null 4 | name: 'Show Sub-Title' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: false 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/showTechnologiesLinks--eecc24bf-e253-43b8-b327-632e0dc07fa6.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showTechnologiesLinks 3 | instructions: null 4 | name: 'Show Technologies Links' 5 | searchable: true 6 | settings: 7 | addRowLabel: 'Add a row' 8 | columns: 9 | __assoc__: 10 | - 11 | - col1 12 | - 13 | __assoc__: 14 | - 15 | - heading 16 | - 'Link Name' 17 | - 18 | - handle 19 | - linkName 20 | - 21 | - width 22 | - '' 23 | - 24 | - type 25 | - singleline 26 | - 27 | - col2 28 | - 29 | __assoc__: 30 | - 31 | - heading 32 | - 'Link URL' 33 | - 34 | - handle 35 | - linkUrl 36 | - 37 | - width 38 | - '' 39 | - 40 | - type 41 | - singleline 42 | maxRows: null 43 | minRows: null 44 | staticRows: false 45 | translationKeyFormat: null 46 | translationMethod: none 47 | type: craft\fields\Table 48 | -------------------------------------------------------------------------------- /cms/config/project/fields/showTitle--a8f2ec1a-a218-451c-a658-e3c600ddb5fa.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showTitle 3 | instructions: null 4 | name: 'Show Title' 5 | searchable: true 6 | settings: 7 | byteLimit: null 8 | charLimit: null 9 | code: false 10 | initialRows: 4 11 | multiline: false 12 | placeholder: null 13 | uiMode: normal 14 | translationKeyFormat: null 15 | translationMethod: none 16 | type: craft\fields\PlainText 17 | -------------------------------------------------------------------------------- /cms/config/project/fields/showUrl--428ec106-b2d1-4d48-a5fa-de192155dff5.yaml: -------------------------------------------------------------------------------- 1 | columnSuffix: null 2 | handle: showUrl 3 | instructions: null 4 | name: 'Show URL' 5 | searchable: true 6 | settings: 7 | fullGraphqlData: false 8 | maxLength: 255 9 | showLabelField: false 10 | types: 11 | - entry 12 | - url 13 | translationKeyFormat: null 14 | translationMethod: none 15 | type: craft\fields\Link 16 | -------------------------------------------------------------------------------- /cms/config/project/sections/about--486a0853-47b2-4509-97ad-43fe3ec42074.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: cc4ea2bd-3bde-4bad-8f72-272fcc3c2a19 # About 6 | handle: about 7 | maxAuthors: 1 8 | name: About 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: about/index 24 | uriFormat: about 25 | type: single 26 | -------------------------------------------------------------------------------- /cms/config/project/sections/calendar--a1eaefb7-b32a-436d-a218-3fc7be02c917.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: 7f6ad724-41b7-4a93-bef9-7de87d1bb23e # Calendar 6 | handle: calendar 7 | maxAuthors: 1 8 | name: Calendar 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: calendar/index 24 | uriFormat: calendar 25 | type: single 26 | -------------------------------------------------------------------------------- /cms/config/project/sections/episodes--c1f6af30-7375-4feb-92ef-a3ed16ba69b2.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: 913ea665-c268-4177-8054-fe76f80101c6 # Episodes 6 | handle: episodes 7 | maxAuthors: 1 8 | name: Episodes 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: episodes/_entry 24 | uriFormat: 'episodes/{slug}' 25 | type: channel 26 | -------------------------------------------------------------------------------- /cms/config/project/sections/episodesIndex--1a66bf43-6fcc-4a78-bf36-0f350b930430.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: 50012289-791c-48b2-8df1-31a8f5eb5380 # Episodes Index 6 | handle: episodesIndex 7 | maxAuthors: 1 8 | name: 'Episodes Index' 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: episodes/index 24 | uriFormat: episodes 25 | type: single 26 | -------------------------------------------------------------------------------- /cms/config/project/sections/genericError--519413e8-a432-4cfe-98c5-5f81e9519f2a.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: e81379aa-e0c7-45c0-b506-c4ab8fce6bce # Generic Error 6 | handle: genericError 7 | maxAuthors: 1 8 | name: 'Generic Error' 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: error.twig 24 | uriFormat: error 25 | type: single 26 | -------------------------------------------------------------------------------- /cms/config/project/sections/guests--214e4dc6-a454-4df0-a1f5-cd94ecdab53f.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: true 3 | entryTypes: 4 | - 5 | uid: 032dc0eb-27cf-4034-ad36-dc8c274a455e # Guests 6 | handle: guests 7 | maxAuthors: 1 8 | name: Guests 9 | propagationMethod: all 10 | siteSettings: 11 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 12 | enabledByDefault: true 13 | hasUrls: false 14 | template: null 15 | uriFormat: null 16 | type: channel 17 | -------------------------------------------------------------------------------- /cms/config/project/sections/homepage--a9d3a609-1f18-4cb7-afc3-3c103a7e09de.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: 9aae2c4b-7316-4ee9-a2d1-41474766b361 # Homepage 6 | handle: homepage 7 | maxAuthors: 1 8 | name: Homepage 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: index.twig 24 | uriFormat: __home__ 25 | type: single 26 | -------------------------------------------------------------------------------- /cms/config/project/sections/notFound--52b673e7-3d80-44a4-94f7-43eaafcc9d6f.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: 78ad1f1e-5dc5-4cff-b19f-43aa4ec02869 # 404 Not Found 6 | handle: notFound 7 | maxAuthors: 1 8 | name: '404 Not Found' 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: 404.twig 24 | uriFormat: '404' 25 | type: single 26 | -------------------------------------------------------------------------------- /cms/config/project/sections/serviceUnavailable--9089688f-6602-4d69-91cd-ec9a94c4bc6f.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: 29da80bf-c705-441b-be33-96df307c84c6 # 503 Service Unavailable 6 | handle: serviceUnavailable 7 | maxAuthors: 1 8 | name: '503 Service Unavailable' 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: 503.twig 24 | uriFormat: '503' 25 | type: single 26 | -------------------------------------------------------------------------------- /cms/config/project/sections/siteOffline--5f70b9e0-f42b-4fdb-bcf6-5e82691d89de.yaml: -------------------------------------------------------------------------------- 1 | defaultPlacement: end 2 | enableVersioning: false 3 | entryTypes: 4 | - 5 | uid: a4be3483-f316-4f96-8820-3914ad7b863a # Site Offline 6 | handle: siteOffline 7 | maxAuthors: 1 8 | name: 'Site Offline' 9 | previewTargets: 10 | - 11 | __assoc__: 12 | - 13 | - label 14 | - 'Primary entry page' 15 | - 16 | - urlFormat 17 | - '{url}' 18 | propagationMethod: all 19 | siteSettings: 20 | 2a4761bd-2461-4db9-96a0-4f52b8cef633: # devMode 21 | enabledByDefault: true 22 | hasUrls: true 23 | template: offline.twig 24 | uriFormat: offline 25 | type: single 26 | -------------------------------------------------------------------------------- /cms/config/project/siteGroups/34348a98-83b9-4f2d-8e14-0437ec964a15.yaml: -------------------------------------------------------------------------------- 1 | name: devMode 2 | -------------------------------------------------------------------------------- /cms/config/project/sites/default--2a4761bd-2461-4db9-96a0-4f52b8cef633.yaml: -------------------------------------------------------------------------------- 1 | baseUrl: '@web' 2 | enabled: true 3 | handle: default 4 | hasUrls: true 5 | language: en-US 6 | name: devMode 7 | primary: true 8 | siteGroup: 34348a98-83b9-4f2d-8e14-0437ec964a15 # devMode 9 | sortOrder: 1 10 | -------------------------------------------------------------------------------- /cms/config/project/tagGroups/episodes--fc24a736-c435-4d8a-aeb3-6105afce1d91.yaml: -------------------------------------------------------------------------------- 1 | fieldLayouts: 2 | 01afbf32-7231-46a1-9f91-1973689d81f7: 3 | tabs: 4 | - 5 | elementCondition: null 6 | elements: 7 | - 8 | autocapitalize: true 9 | autocomplete: false 10 | autocorrect: true 11 | class: null 12 | dateAdded: '2025-02-02T04:38:03+00:00' 13 | disabled: false 14 | elementCondition: null 15 | id: null 16 | includeInCards: false 17 | inputType: null 18 | instructions: null 19 | label: null 20 | max: null 21 | min: null 22 | name: null 23 | orientation: null 24 | placeholder: null 25 | providesThumbs: false 26 | readonly: false 27 | requirable: false 28 | size: null 29 | step: null 30 | tip: null 31 | title: null 32 | type: craft\fieldlayoutelements\TitleField 33 | uid: f3ccf97b-4996-4b20-b9d6-36a48a888f49 34 | userCondition: null 35 | warning: null 36 | width: 100 37 | name: Content 38 | uid: 4089a4ed-d9bc-4fe0-8b65-51b2a3fe04c7 39 | userCondition: null 40 | handle: episodes 41 | name: Episodes 42 | -------------------------------------------------------------------------------- /cms/config/project/users/groups/hosts--19dfdfbb-837c-46d5-87bf-e6540df98dc4.yaml: -------------------------------------------------------------------------------- 1 | description: null 2 | handle: hosts 3 | name: Hosts 4 | permissions: 5 | - accesscp 6 | - accesscpwhensystemisoff 7 | - accessplugin-retour 8 | - accessplugin-seomatic 9 | - 'assignusergroup:19dfdfbb-837c-46d5-87bf-e6540df98dc4' # Hosts 10 | - 'createfoldersinvolume:ab5dbb6f-b2fe-4712-9237-d47c3a608050' 11 | - 'retour:dashboard' 12 | - 'retour:redirects' 13 | - 'retour:settings' 14 | - 'saveassetinvolume:808914da-7ca2-4bb3-89ad-6c46b0369470' 15 | - 'saveassetinvolume:ab5dbb6f-b2fe-4712-9237-d47c3a608050' 16 | - 'saveassetinvolume:cd231c31-8caf-4b13-995d-2b84f9750c63' 17 | - 'saveentries:c1f6af30-7375-4feb-92ef-a3ed16ba69b2' # Episodes 18 | - 'savepeerentries:c1f6af30-7375-4feb-92ef-a3ed16ba69b2' # Episodes 19 | - 'savepeerentrydrafts:c1f6af30-7375-4feb-92ef-a3ed16ba69b2' # Episodes 20 | - 'seomatic:content-meta' 21 | - 'seomatic:content-meta:facebook' 22 | - 'seomatic:content-meta:general' 23 | - 'seomatic:content-meta:sitemap' 24 | - 'seomatic:content-meta:twitter' 25 | - 'seomatic:dashboard' 26 | - 'seomatic:global-meta' 27 | - 'seomatic:global-meta:ads' 28 | - 'seomatic:global-meta:facebook' 29 | - 'seomatic:global-meta:general' 30 | - 'seomatic:global-meta:humans' 31 | - 'seomatic:global-meta:robots' 32 | - 'seomatic:global-meta:twitter' 33 | - 'seomatic:plugin-settings' 34 | - 'seomatic:site-settings' 35 | - 'seomatic:site-settings:creator' 36 | - 'seomatic:site-settings:identity' 37 | - 'seomatic:site-settings:miscellaneous' 38 | - 'seomatic:site-settings:sitemap' 39 | - 'seomatic:site-settings:social' 40 | - 'seomatic:tracking-scripts' 41 | - 'seomatic:tracking-scripts:facebookpixel' 42 | - 'seomatic:tracking-scripts:googleanalytics' 43 | - 'seomatic:tracking-scripts:googletagmanager' 44 | - 'seomatic:tracking-scripts:gtag' 45 | - 'seomatic:tracking-scripts:hubspot' 46 | - 'seomatic:tracking-scripts:linkedininsight' 47 | - 'utility:php-info' 48 | - 'utility:system-report' 49 | - 'viewentries:c1f6af30-7375-4feb-92ef-a3ed16ba69b2' # Episodes 50 | - 'viewpeerentries:c1f6af30-7375-4feb-92ef-a3ed16ba69b2' # Episodes 51 | - 'viewpeerentrydrafts:c1f6af30-7375-4feb-92ef-a3ed16ba69b2' # Episodes 52 | - 'viewvolume:808914da-7ca2-4bb3-89ad-6c46b0369470' 53 | - 'viewvolume:ab5dbb6f-b2fe-4712-9237-d47c3a608050' 54 | - 'viewvolume:cd231c31-8caf-4b13-995d-2b84f9750c63' 55 | -------------------------------------------------------------------------------- /cms/config/project/users/groups/owners--9436ac5e-44de-4fe9-be59-fd1f0fc26941.yaml: -------------------------------------------------------------------------------- 1 | description: null 2 | handle: owners 3 | name: Owners 4 | -------------------------------------------------------------------------------- /cms/config/project/users/users.yaml: -------------------------------------------------------------------------------- 1 | allowPublicRegistration: false 2 | deactivateByDefault: false 3 | defaultGroup: '' 4 | photoSubpath: '' 5 | photoVolumeUid: 98f56e95-4be6-4238-a110-1f21574fa642 # Devmode Users 6 | requireEmailVerification: true 7 | -------------------------------------------------------------------------------- /cms/config/project/volumes/devmodeEpisodes--e69c8edb-d562-4367-9a05-91a6fd2c7d99.yaml: -------------------------------------------------------------------------------- 1 | altTranslationKeyFormat: null 2 | altTranslationMethod: site 3 | fieldLayouts: 4 | 7d2a2649-a608-461b-8c02-e4d6f0436509: 5 | tabs: 6 | - 7 | elementCondition: null 8 | elements: 9 | - 10 | autocapitalize: true 11 | autocomplete: false 12 | autocorrect: true 13 | class: null 14 | dateAdded: '2025-02-02T04:38:03+00:00' 15 | disabled: false 16 | elementCondition: null 17 | id: null 18 | includeInCards: false 19 | inputType: null 20 | instructions: null 21 | label: null 22 | max: null 23 | min: null 24 | name: null 25 | orientation: null 26 | placeholder: null 27 | providesThumbs: false 28 | readonly: false 29 | requirable: false 30 | size: null 31 | step: null 32 | tip: null 33 | title: null 34 | type: craft\fieldlayoutelements\assets\AssetTitleField 35 | uid: 954bb0de-6c5d-4230-84db-a9f3d50ba148 36 | userCondition: null 37 | warning: null 38 | width: 100 39 | name: Content 40 | uid: 2a1dc600-48d5-4339-8b9e-87d4751d591f 41 | userCondition: null 42 | fs: devmodeEpisodes 43 | handle: devmodeEpisodes 44 | name: 'Devmode Episodes' 45 | sortOrder: 4 46 | subpath: '' 47 | titleTranslationKeyFormat: null 48 | titleTranslationMethod: site 49 | transformFs: null 50 | transformSubpath: '' 51 | -------------------------------------------------------------------------------- /cms/config/project/volumes/devmodeSite--7540db37-7ec3-4471-9de6-36bde06e949a.yaml: -------------------------------------------------------------------------------- 1 | altTranslationKeyFormat: null 2 | altTranslationMethod: site 3 | fieldLayouts: 4 | a3429f83-028c-4ceb-954f-7cfe44643b98: 5 | tabs: 6 | - 7 | elementCondition: null 8 | elements: 9 | - 10 | autocapitalize: true 11 | autocomplete: false 12 | autocorrect: true 13 | class: null 14 | dateAdded: '2025-02-02T04:38:03+00:00' 15 | disabled: false 16 | elementCondition: null 17 | id: null 18 | includeInCards: false 19 | inputType: null 20 | instructions: null 21 | label: null 22 | max: null 23 | min: null 24 | name: null 25 | orientation: null 26 | placeholder: null 27 | providesThumbs: false 28 | readonly: false 29 | requirable: false 30 | size: null 31 | step: null 32 | tip: null 33 | title: null 34 | type: craft\fieldlayoutelements\assets\AssetTitleField 35 | uid: e2d3c1f9-715b-4a6f-bf79-16334cdc9c41 36 | userCondition: null 37 | warning: null 38 | width: 100 39 | - 40 | dateAdded: '2025-02-02T04:38:03+00:00' 41 | elementCondition: null 42 | fieldUid: 1be1c156-82fa-4f08-bb63-6d3417da2844 # Optimized Images 43 | handle: null 44 | includeInCards: false 45 | instructions: null 46 | label: null 47 | providesThumbs: false 48 | required: false 49 | tip: null 50 | type: craft\fieldlayoutelements\CustomField 51 | uid: 3ecb4901-10ca-4deb-8489-d9b32da18386 52 | userCondition: null 53 | warning: null 54 | width: 100 55 | name: Content 56 | uid: 54f3f7c7-8909-447a-8fc7-637bd9f72b85 57 | userCondition: null 58 | fs: devmodeSite 59 | handle: devmodeSite 60 | name: 'Devmode Site' 61 | sortOrder: 5 62 | subpath: '' 63 | titleTranslationKeyFormat: null 64 | titleTranslationMethod: site 65 | transformFs: null 66 | transformSubpath: '' 67 | -------------------------------------------------------------------------------- /cms/config/project/volumes/devmodeTranscripts--bd8ef0d7-f73b-4138-ac52-c14d11dd780e.yaml: -------------------------------------------------------------------------------- 1 | altTranslationKeyFormat: null 2 | altTranslationMethod: site 3 | fieldLayouts: 4 | 3eb40d2e-5571-4c14-a5df-2a714e403859: 5 | tabs: 6 | - 7 | elementCondition: null 8 | elements: 9 | - 10 | autocapitalize: true 11 | autocomplete: false 12 | autocorrect: true 13 | class: null 14 | dateAdded: '2025-02-02T04:38:03+00:00' 15 | disabled: false 16 | elementCondition: null 17 | id: null 18 | includeInCards: false 19 | inputType: null 20 | instructions: null 21 | label: null 22 | max: null 23 | min: null 24 | name: null 25 | orientation: null 26 | placeholder: null 27 | providesThumbs: false 28 | readonly: false 29 | requirable: false 30 | size: null 31 | step: null 32 | tip: null 33 | title: null 34 | type: craft\fieldlayoutelements\assets\AssetTitleField 35 | uid: 71011448-5b56-4440-9f84-b3c21070895e 36 | userCondition: null 37 | warning: null 38 | width: 100 39 | name: Content 40 | uid: 3d04041a-2f11-4290-b572-72d21c4a0308 41 | userCondition: null 42 | fs: devmodeTranscripts 43 | handle: devmodeTranscripts 44 | name: 'Devmode Transcripts' 45 | sortOrder: 7 46 | subpath: '' 47 | titleTranslationKeyFormat: null 48 | titleTranslationMethod: site 49 | transformFs: null 50 | transformSubpath: '' 51 | -------------------------------------------------------------------------------- /cms/config/project/volumes/devmodeUsers--98f56e95-4be6-4238-a110-1f21574fa642.yaml: -------------------------------------------------------------------------------- 1 | altTranslationKeyFormat: null 2 | altTranslationMethod: site 3 | fieldLayouts: 4 | 20e7215a-39c8-421f-835a-f14244493bd7: 5 | tabs: 6 | - 7 | elementCondition: null 8 | elements: 9 | - 10 | autocapitalize: true 11 | autocomplete: false 12 | autocorrect: true 13 | class: null 14 | dateAdded: '2025-02-02T04:38:03+00:00' 15 | disabled: false 16 | elementCondition: null 17 | id: null 18 | includeInCards: false 19 | inputType: null 20 | instructions: null 21 | label: null 22 | max: null 23 | min: null 24 | name: null 25 | orientation: null 26 | placeholder: null 27 | providesThumbs: false 28 | readonly: false 29 | requirable: false 30 | size: null 31 | step: null 32 | tip: null 33 | title: null 34 | type: craft\fieldlayoutelements\assets\AssetTitleField 35 | uid: 65c7f274-fec9-4300-a010-a044335719aa 36 | userCondition: null 37 | warning: null 38 | width: 100 39 | - 40 | dateAdded: '2025-02-02T04:38:03+00:00' 41 | elementCondition: null 42 | fieldUid: 41fdb4c8-4774-4101-918f-1412190b085b # Profile Optimized Images 43 | handle: null 44 | includeInCards: false 45 | instructions: null 46 | label: null 47 | providesThumbs: false 48 | required: false 49 | tip: null 50 | type: craft\fieldlayoutelements\CustomField 51 | uid: 71a9ed50-c065-4828-beac-73ef05a3dcd7 52 | userCondition: null 53 | warning: null 54 | width: 100 55 | name: Content 56 | uid: 1cf35a61-9078-4f4c-8220-cd93ab809da3 57 | userCondition: null 58 | fs: devmodeUsers 59 | handle: devmodeUsers 60 | name: 'Devmode Users' 61 | sortOrder: 6 62 | subpath: '' 63 | titleTranslationKeyFormat: null 64 | titleTranslationMethod: site 65 | transformFs: null 66 | transformSubpath: '' 67 | -------------------------------------------------------------------------------- /cms/config/redactor/Simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "buttons": ["bold", "italic"], 3 | "toolbarFixed": true 4 | } 5 | -------------------------------------------------------------------------------- /cms/config/redactor/Standard.json: -------------------------------------------------------------------------------- 1 | { 2 | "buttons": [ 3 | "formatting", 4 | "bold", 5 | "italic", 6 | "unorderedlist", 7 | "orderedlist", 8 | "link", 9 | "image", 10 | "video" 11 | ], 12 | "plugins": [ 13 | "fullscreen", 14 | "video" 15 | ], 16 | "toolbarFixed": true 17 | } -------------------------------------------------------------------------------- /cms/config/routes.php: -------------------------------------------------------------------------------- 1 | ' => ['template' => 'blog/_archive'], 15 | * 16 | * That example would match URIs such as `/blog/archive/2012`, and pass the 17 | * request along to the `blog/_archive` template, providing it a `year` variable 18 | * set to the value `2012`. 19 | */ 20 | 21 | return [ 22 | /** 23 | * Handler for URLs of the format https://devMode.fm/ 24 | * which are unfortunately used in the `guid` field in the RSS feed 25 | * and so get crawled by Google, yet cannot be changed or RSS readers 26 | * will think they are new episodes, and download them. 27 | */ 28 | '' => ['template' => 'episodes/_entry'], 29 | '/amp' => ['template' => 'episodes/_amp-entry'], 30 | // Player card for Twitter cards handler 31 | 'player-card/' => ['template' => 'player-card'], 32 | // Google AMP handlers 33 | 'episodes//amp' => ['template' => 'episodes/_amp-entry'], 34 | 'about/amp' => ['template' => 'about/amp-index'], 35 | 'calendar/amp' => ['template' => 'calendar/amp-index'], 36 | 'episodes/amp' => ['template' => 'episodes/amp-index'], 37 | 'amp' => ['template' => 'amp-index'], 38 | ]; 39 | -------------------------------------------------------------------------------- /cms/config/seomatic-config/globalmeta/Creator.php: -------------------------------------------------------------------------------- 1 | [ 20 | 'siteType' => 'Organization', 21 | 'siteSubType' => '', 22 | 'siteSpecificType' => '', 23 | 'computedType' => 'Organization', 24 | 'genericName' => 'nystudio107', 25 | 'genericAlternateName' => 'nys', 26 | 'genericDescription' => 'We do technology-based consulting, branding, design, and development. Making the web better one site at a time, with a focus on performance, usability & SEO', 27 | 'genericUrl' => 'https://nystudio107.com/', 28 | 'genericImage' => 'https://nystudio107-ems2qegf7x6qiqq.netdna-ssl.com/img/site/nys_logo_seo.png', 29 | 'genericImageWidth' => '1042', 30 | 'genericImageHeight' => '1042', 31 | 'genericImageIds' => [], 32 | 'genericTelephone' => '', 33 | 'genericEmail' => 'info@nystudio107.com', 34 | 'genericStreetAddress' => '', 35 | 'genericAddressLocality' => 'Webster', 36 | 'genericAddressRegion' => 'NY', 37 | 'genericPostalCode' => '14580', 38 | 'genericAddressCountry' => 'US', 39 | 'genericGeoLatitude' => '43.2365384', 40 | 'genericGeoLongitude' => '-77.49211620000001', 41 | 'personGender' => '', 42 | 'personBirthPlace' => '', 43 | 'organizationDuns' => '', 44 | 'organizationFounder' => 'Andrew Welch, Polly Welch', 45 | 'organizationFoundingDate' => '2013-05-02', 46 | 'organizationFoundingLocation' => 'Webster, NY', 47 | 'organizationContactPoints' => [], 48 | 'corporationTickerSymbol' => '', 49 | 'localBusinessPriceRange' => '', 50 | 'localBusinessOpeningHours' => [], 51 | 'restaurantServesCuisine' => '', 52 | 'restaurantMenuUrl' => '', 53 | 'restaurantReservationsUrl' => '', 54 | ], 55 | ]; 56 | -------------------------------------------------------------------------------- /cms/config/twigpack.php: -------------------------------------------------------------------------------- 1 | App::env('DEV_MODE'), 31 | // The JavaScript entry from the manifest.json to inject on Twig error pages 32 | 'errorEntry' => ['runtime.js', 'app.js'], 33 | // Manifest file names 34 | 'manifest' => [ 35 | 'legacy' => 'manifest-legacy.json', 36 | 'modern' => 'manifest.json', 37 | ], 38 | // Public server config 39 | 'server' => [ 40 | 'manifestPath' => '@webroot/dist/', 41 | 'publicPath' => '/', 42 | ], 43 | // webpack-dev-server config 44 | 'devServer' => [ 45 | 'manifestPath' => App::env('TWIGPACK_DEV_SERVER_MANIFEST_PATH'), 46 | 'publicPath' => App::env('TWIGPACK_DEV_SERVER_PUBLIC_PATH'), 47 | ], 48 | // Bundle to use with the webpack-dev-server 49 | 'devServerBuildType' => 'modern', 50 | // Whether to include a Content Security Policy "nonce" for inline 51 | // CSS or JavaScript. Valid values are 'header' or 'tag' for how the CSP 52 | // should be included. c.f.: 53 | // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#Unsafe_inline_script 54 | 'cspNonce' => '', 55 | // Local files config 56 | 'localFiles' => [ 57 | 'basePath' => '@webroot/', 58 | 'criticalPrefix' => 'dist/criticalcss/', 59 | 'criticalSuffix' => '_critical.min.css', 60 | ], 61 | ]; 62 | -------------------------------------------------------------------------------- /cms/craft: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 14 | exit($exitCode); 15 | -------------------------------------------------------------------------------- /cms/craft.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem ------------------------------------------------------------- 4 | rem Craft command line bootstrap script for Windows 5 | rem ------------------------------------------------------------- 6 | 7 | @setlocal 8 | 9 | set CRAFT_PATH=%~dp0 10 | 11 | if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe 12 | 13 | "%PHP_COMMAND%" "%CRAFT_PATH%craft" %* 14 | 15 | @endlocal 16 | -------------------------------------------------------------------------------- /cms/example.env: -------------------------------------------------------------------------------- 1 | # Craft general settings 2 | ALLOW_UPDATES=1 3 | ALLOW_ADMIN_CHANGES=1 4 | BACKUP_ON_UPDATE=0 5 | DEV_MODE=1 6 | ENABLE_TEMPLATE_CACHING=0 7 | ENVIRONMENT=local 8 | RUN_QUEUE_AUTOMATICALLY=0 9 | SECURITY_KEY=FnKtqveecwgMavLwQnX2I-dqYjpwZMR6 10 | 11 | # Craft database settings 12 | DB_DSN=pgsql:host=postgres;port=5432;dbname=project 13 | DB_USER=project 14 | DB_PASSWORD=project 15 | DB_SCHEMA=public 16 | DB_TABLE_PREFIX= 17 | 18 | # URL & path settings 19 | ASSETS_URL=http://localhost:8000/ 20 | SITE_URL=http://localhost:8000/ 21 | WEB_ROOT_PATH=/var/www/project/cms/web 22 | 23 | # Craft & Plugin Licenses 24 | LICENSE_KEY= 25 | PLUGIN_IMAGEOPTIMIZE_LICENSE= 26 | PLUGIN_RETOUR_LICENSE= 27 | PLUGIN_SEOMATIC_LICENSE= 28 | PLUGIN_TRANSCODER_LICENSE= 29 | PLUGIN_WEBPERF_LICENSE= 30 | 31 | # S3 settings 32 | S3_KEY_ID=REPLACE_ME 33 | S3_SECRET=REPLACE_ME 34 | S3_BUCKET=devmode-bucket 35 | S3_REGION=us-east-2 36 | S3_SUBFOLDER= 37 | 38 | # CloudFront settings 39 | CLOUDFRONT_URL=https://dnzwsrj1eic0g.cloudfront.net 40 | CLOUDFRONT_DISTRIBUTION_ID=E17SKV1U1OTZKW 41 | CLOUDFRONT_PATH_PREFIX= 42 | SERVERLESS_SHARP_CLOUDFRONT_URL=https://d2ogb6ehvsyfwp.cloudfront.net 43 | 44 | # Redis settings 45 | REDIS_HOSTNAME=redis 46 | REDIS_PORT=6379 47 | REDIS_DEFAULT_DB=0 48 | REDIS_CRAFT_DB=3 49 | 50 | # Vite settings 51 | VITE_DEV_SERVER_PUBLIC=http://localhost:3000/ 52 | VITE_DEV_SERVER_INTERNAL=http://vite:3000/ 53 | 54 | # Disqus settings 55 | DISQUS_PUBLIC_KEY= 56 | DISQUS_SECRET_KEY= 57 | 58 | # Google Analytics settings 59 | GA_TRACKING_ID=UA-69117511-5 60 | 61 | # FastCGI Cache Bust settings 62 | FAST_CGI_CACHE_PATH= 63 | 64 | # Xdebug Settings 65 | DBGP_IDEKEY=phpstorm 66 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/.craftplugin: -------------------------------------------------------------------------------- 1 | {"pluginName":"Site","pluginDescription":"An example module for Craft CMS 3 that lets you enhance your websites with a custom site module","pluginVersion":"1.0.0","pluginAuthorName":"nystudio107","pluginVendorName":"nystudio107","pluginAuthorUrl":"https://nystudio107.com/","codeComments":[],"pluginComponents":[],"apiVersion":"module_api_version_3_0"} -------------------------------------------------------------------------------- /cms/modules/sitemodule/.gitignore: -------------------------------------------------------------------------------- 1 | # CRAFT ENVIRONMENT 2 | .env.php 3 | .env.sh 4 | .env 5 | 6 | # COMPOSER 7 | /vendor 8 | 9 | # BUILD FILES 10 | /bower_components/* 11 | /node_modules/* 12 | /build/* 13 | /yarn-error.log 14 | 15 | # MISC FILES 16 | .cache 17 | .DS_Store 18 | .idea 19 | .project 20 | .settings 21 | *.esproj 22 | *.sublime-workspace 23 | *.sublime-project 24 | *.tmproj 25 | *.tmproject 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | config.codekit3 32 | prepros-6.config 33 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Site Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## 1.0.0 - 2018-01-19 8 | ### Added 9 | - Initial release 10 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 nystudio107 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /cms/modules/sitemodule/README.md: -------------------------------------------------------------------------------- 1 | # Site module for Craft CMS 3.x 2 | 3 | An example module for Craft CMS 3 that lets you enhance your websites with a custom site module 4 | 5 | ## Requirements 6 | 7 | This module requires Craft CMS 3.0.0-RC1 or later. 8 | 9 | ## Installation 10 | 11 | To install the module, follow these instructions. 12 | 13 | First, you'll need to add the contents of the `app.php` file to your `config/app.php` (or just copy it there if it does not exist). This ensures that your module will get loaded for each request. The file might look something like this: 14 | ``` 15 | return [ 16 | 'modules' => [ 17 | 'site-module' => [ 18 | 'class' => \modules\sitemodule\SiteModule::class, 19 | ], 20 | ], 21 | 'bootstrap' => ['site-module'], 22 | ]; 23 | ``` 24 | You'll also need to make sure that you add the following to your project's `composer.json` file so that Composer can find your module: 25 | 26 | "autoload": { 27 | "psr-4": { 28 | "modules\\sitemodule\\": "modules/sitemodule/src/" 29 | } 30 | }, 31 | 32 | After you have added this, you will need to do: 33 | 34 | composer dump-autoload 35 | 36 | …from the project’s root directory, to rebuild the Composer autoload map. This will happen automatically any time you do a `composer install` or `composer update` as well. 37 | 38 | ## Site Overview 39 | 40 | -Insert text here- 41 | 42 | ## Using Site 43 | 44 | -Insert text here- 45 | 46 | ## Site Roadmap 47 | 48 | Some things to do, and ideas for potential features: 49 | 50 | * Release it 51 | 52 | Brought to you by [nystudio107](https://nystudio107.com/) 53 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/src/assetbundles/sitemodule/SiteModuleAsset.php: -------------------------------------------------------------------------------- 1 | sourcePath = "@modules/sitemodule/assetbundles/sitemodule/dist"; 32 | 33 | $this->depends = [ 34 | CpAsset::class, 35 | ]; 36 | 37 | $this->js = [ 38 | 'js/SiteModule.js', 39 | ]; 40 | 41 | $this->css = [ 42 | 'css/SiteModule.css', 43 | ]; 44 | 45 | parent::init(); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/src/assetbundles/sitemodule/dist/css/SiteModule.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Site module for Craft CMS 3 | * 4 | * Site CSS 5 | * 6 | * @author nystudio107 7 | * @copyright Copyright (c) 2018 nystudio107 8 | * @link https://nystudio107.com/ 9 | * @package SiteModule 10 | * @since 1.0.0 11 | */ 12 | 13 | body.login { 14 | background-size: 600px; 15 | background-repeat: repeat; 16 | background-image: url('/img/site/devmode-fm-light-bg-opaque.svg'); 17 | } 18 | 19 | body.login label, body.login #forgot-password { 20 | background-color: #FFF; 21 | } 22 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/src/assetbundles/sitemodule/dist/img/SiteModule-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 14 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/src/assetbundles/sitemodule/dist/js/SiteModule.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Site module for Craft CMS 3 | * 4 | * Site JS 5 | * 6 | * @author nystudio107 7 | * @copyright Copyright (c) 2018 nystudio107 8 | * @link https://nystudio107.com/ 9 | * @package SiteModule 10 | * @since 1.0.0 11 | */ 12 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/src/config.php: -------------------------------------------------------------------------------- 1 | getConfig()->env; 44 | 45 | // Try craft/config first 46 | $path = Craft::getAlias('@config/' . $fileName, false); 47 | if ($path === false || !file_exists($path)) { 48 | // Now try our own internal config 49 | $path = Craft::getAlias('@modules/sitemodule/' . $fileName, false); 50 | if ($path === false || !file_exists($path)) { 51 | return []; 52 | } 53 | } 54 | 55 | if (!is_array($config = @include $path)) { 56 | return []; 57 | } 58 | 59 | // If it's not a multi-environment config, return the whole thing 60 | if (!array_key_exists('*', $config)) { 61 | return $config; 62 | } 63 | 64 | // If no environment was specified, just look in the '*' array 65 | if ($currentEnv === null) { 66 | return $config['*']; 67 | } 68 | 69 | $mergedConfig = []; 70 | foreach ($config as $env => $envConfig) { 71 | if ($env === '*' || StringHelper::contains($currentEnv, $env)) { 72 | $mergedConfig = ArrayHelper::merge($mergedConfig, $envConfig); 73 | } 74 | } 75 | 76 | return $mergedConfig; 77 | } 78 | 79 | // Private Methods 80 | // ========================================================================= 81 | } 82 | 83 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/src/services/Calendar.php: -------------------------------------------------------------------------------- 1 | api->client; 37 | try { 38 | $response = $client->get($url, ['http_errors' => false]); 39 | $statusCode = $response->getStatusCode(); 40 | if ($statusCode === 200) { 41 | $result = $response->getBody()->getContents(); 42 | } else { 43 | $reason = $response->getReasonPhrase(); 44 | Craft::error("Invalid response from API: ${reason} -- ${url}", __METHOD__); 45 | } 46 | } catch (Throwable $e) { 47 | Craft::error($e->getMessage() . " -- ${url}", 'site-module'); 48 | } 49 | 50 | return $result; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/src/translations/en/site-module.php: -------------------------------------------------------------------------------- 1 | '{name} module loaded', 18 | ]; 19 | -------------------------------------------------------------------------------- /cms/modules/sitemodule/src/variables/SiteVariable.php: -------------------------------------------------------------------------------- 1 | remoteFile; 36 | $result = $remoteFile->fetch($url); 37 | if ($result) { 38 | $result = Json::decodeIfJson($result); 39 | } 40 | // Return null if the JSON decode fails 41 | if (is_string($result)) { 42 | $result = null; 43 | } 44 | 45 | return $result; 46 | } 47 | 48 | /** 49 | * Return an array of transcript lines from the remote file URL 50 | * 51 | * @param string $url 52 | * @return array|null 53 | * @throws UnableToProcessCsv 54 | */ 55 | public function getTranscript(string $url): ?array 56 | { 57 | return SiteModule::$instance->transcript->fetch($url); 58 | } 59 | 60 | /** 61 | * Return the URL to the calendar feed 62 | * 63 | * @return string 64 | */ 65 | public function getCalendarFeedUrl(): string 66 | { 67 | return SiteModule::$instance->calendar->getCalendarFeedUrl(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /cms/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/cms/templates/.gitkeep -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_layouts/base-ajax-layout.twig: -------------------------------------------------------------------------------- 1 | {# -- Base layout template that all AJAX requests inherit from -- #} 2 | {# 3 | ┌─────────────────────────────────────────────────────────────────────────────┐ 4 | │ ┌─────────────────────────────────────────────────────────────────────────┐ │ 5 | │ │ │ │ 6 | │ │ │ │ 7 | │ │ │ │ 8 | │ │ content │ │ 9 | │ └─────────────────────────────────────────────────────────────────────────┘ │ 10 | │ │ 11 | │ htmlPage │ 12 | └─────────────────────────────────────────────────────────────────────────────┘ 13 | #} 14 | {% extends "_layouts/global-variables.twig" %} 15 | 16 | {% block htmlPage %} 17 | {% minify %} 18 | {# -- Primary content block -- #} 19 | {% block content %} 20 | No content block defined. 21 | {% endblock content %} 22 | {% endminify %} 23 | {% endblock htmlPage %} 24 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/amp-analytics.twig: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/amp-boilerplate-css.twig: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/amp-head-js.twig: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/body-js.twig: -------------------------------------------------------------------------------- 1 | {# -- Shim to handle lazy image loading if native isn't available -- #} 2 | 5 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/critical-css.twig: -------------------------------------------------------------------------------- 1 | {# -- Critical CSS -- #} 2 | {# 3 | # Use Nginx Server Sider Includes (SSI) to render different HTML depending on 4 | # the value in the `critical-css` cookie. ref: http://nginx.org/en/docs/http/ngx_http_ssi_module.html 5 | #} 6 | {% set cssHash = craft.vite.getCssHash("src/js/app.ts") %} 7 | {# 8 | # If the `critical-css` cookie is set, the client already has the CSS file download, 9 | # so don't include the critical CSS, and load the full stylesheet(s) synchronously 10 | #} 11 | 12 | {{ craft.vite.script("src/js/app.ts", false) }} 13 | 14 | {# 15 | # If the cookie is not set, set the cookie, then include the critical CSS for this page, 16 | # and load the full stylesheet(s) asychronously 17 | #} 18 | 21 | {{ craft.vite.includeCriticalCssTags() }} 22 | {{ craft.vite.script("src/js/app.ts", true) }} 23 | 24 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/head-js.twig: -------------------------------------------------------------------------------- 1 | {# -- Register our Service Worker -- #} 2 | {% if not craft.app.config.general.devMode %} 3 | {% include "_boilerplate/_partials/register-service-worker.twig" %} 4 | {% endif %} 5 | 6 | {# -- Partytown.js -- https://partytown.builder.io/html -- #} 7 | 20 | 21 | {# -- Handle tabs gracefully as per https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 -- #} 22 | {% include "_boilerplate/_partials/tab-handler.twig" %} 23 | 24 | {# -- Tiny Cookie JavaScript -- #} 25 | 28 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/head-meta.twig: -------------------------------------------------------------------------------- 1 | {# -- Basic meta tags -- #} 2 | 3 | 4 | 5 | {# -- Prefetch & preconnect headers and links -- #} 6 | {% set headerLink = "Link: " %} 7 | {% for url in prefetchUrls %} 8 | {% set headerLink = headerLink ~ "<#{url}>; rel=dns-prefetch;," %} 9 | {% set headerLink = headerLink ~ "<#{url}>; rel=preconnect; crossorigin;" %} 10 | {% if not loop.last %} 11 | {% set headerLink = headerLink ~ "," %} 12 | {% endif %} 13 | 14 | 15 | {% endfor %} 16 | {% header headerLink %} 17 | 18 | {# -- Favicons, webapp manifests, etc. -- #} 19 | {{ craft.vite.inline("@webroot/dist/assets/favicons/webapp.html") }} 20 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/register-service-worker.twig: -------------------------------------------------------------------------------- 1 | {# Service Worker was removed due to questionable benefits vs. the caching issues it can present 2 | 15 | #} 16 | {# Unregister any lingering Service Workers #} 17 | 26 | -------------------------------------------------------------------------------- /cms/templates/_boilerplate/_partials/tab-handler.twig: -------------------------------------------------------------------------------- 1 | {# -- Handle tabs gracefully as per https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 -- #} 2 | 10 | 29 | -------------------------------------------------------------------------------- /cms/templates/_inline-css/site-fonts.css: -------------------------------------------------------------------------------- 1 | /* -- Site fonts */ 2 | 3 | /* -- Fontello normal */ 4 | 5 | @font-face { 6 | font-family: fontello; 7 | font-display: swap; 8 | src: url("{{ assetsUrl }}dist/fonts/fontello.eot"); 9 | src: 10 | url("{{ assetsUrl }}dist/fonts/fontello.eot?#iefix") format("embedded-opentype"), 11 | url("{{ assetsUrl }}dist/fonts/fontello.woff2") format("woff2"), 12 | url("{{ assetsUrl }}dist/fonts/fontello.woff") format("woff"), 13 | url("{{ assetsUrl }}dist/fonts/fontello.ttf") format("truetype"), 14 | url("{{ assetsUrl }}dist/fonts/fontello.svg#fontello") format("svg"); 15 | font-weight: normal; 16 | font-style: normal; 17 | } 18 | 19 | /* -- Operator Mono normal */ 20 | 21 | @font-face { 22 | font-family: "Operator Mono"; 23 | font-display: swap; 24 | src: url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-Book.eot"); 25 | src: 26 | url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-Book.eot?#iefix") format("embedded-opentype"), 27 | url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-Book.woff2") format("woff2"), 28 | url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-Book.woff") format("woff"), 29 | url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-Book.ttf") format("truetype"); 30 | font-weight: normal; 31 | font-style: normal; 32 | } 33 | 34 | /* -- Operator Mono italic */ 35 | 36 | @font-face { 37 | font-family: "Operator Mono"; 38 | font-display: swap; 39 | src: url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-BookItalic.eot"); 40 | src: 41 | url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-BookItalic.eot?#iefix") format("embedded-opentype"), 42 | url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-BookItalic.woff2") format("woff2"), 43 | url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-BookItalic.woff") format("woff"), 44 | url("{{ assetsUrl }}dist/fonts/OperatorMonoSSm-BookItalic.ttf") format("truetype"); 45 | font-weight: normal; 46 | font-style: italic; 47 | } 48 | -------------------------------------------------------------------------------- /cms/templates/_inline-js/lazyload-image-shim.js: -------------------------------------------------------------------------------- 1 | // From https://web.dev/native-lazy-loading/#how-do-i-handle-browsers-that-don't-yet-support-native-lazy-loading 2 | if ('loading' in HTMLImageElement.prototype) { 3 | // Replace the img.src with what is in the data-src property 4 | const images = document.querySelectorAll('img[loading="lazy"]'); 5 | images.forEach(img => { 6 | img.src = img.dataset.src; 7 | }); 8 | // Replace the source.srcset with what is in the data-srcset property 9 | const sources = document.querySelectorAll('source[data-srcset]') 10 | sources.forEach(source => { 11 | source.srcset = source.dataset.srcset; 12 | }); 13 | } else { 14 | // Dynamically import the LazySizes library 15 | const script = document.createElement('script'); 16 | script.type = 'module'; 17 | script.src = 18 | '{{ craft.vite.entry("src/js/utils/lazysizes-wrapper.ts") }}'; 19 | document.body.appendChild(script); 20 | } 21 | -------------------------------------------------------------------------------- /cms/templates/_inline-js/tiny-cookie.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.Cookie=t()}(this,function(){"use strict";function e(t,n,o){return void 0===n?e.get(t):void(null===n?e.remove(t):e.set(t,n,o))}function t(e){return e.replace(/[.*+?^$|[\](){}\\-]/g,"\\$&")}function n(e){var t="";for(var n in e)if(e.hasOwnProperty(n)){if("expires"===n){var r=e[n];"object"!=typeof r&&(r+="number"==typeof r?"D":"",r=o(r)),e[n]=r.toUTCString()}if("secure"===n){if(!e[n])continue;t+=";"+n}t+=";"+n+"="+e[n]}return e.hasOwnProperty("path")||(t+=";path=/"),t}function o(e){var t=new Date,n=e.charAt(e.length-1),o=parseInt(e,10);switch(n){case"Y":t.setFullYear(t.getFullYear()+o);break;case"M":t.setMonth(t.getMonth()+o);break;case"D":t.setDate(t.getDate()+o);break;case"h":t.setHours(t.getHours()+o);break;case"m":t.setMinutes(t.getMinutes()+o);break;case"s":t.setSeconds(t.getSeconds()+o);break;default:t=new Date(e)}return t}return e.enabled=function(){var t,n="__test_key";return document.cookie=n+"=1",t=!!document.cookie,t&&e.remove(n),t},e.get=function(e,n){if("string"!=typeof e||!e)return null;e="(?:^|; )"+t(e)+"(?:=([^;]*?))?(?:;|$)";var o=new RegExp(e),r=o.exec(document.cookie);return null!==r?n?r[1]:decodeURIComponent(r[1]):null},e.getRaw=function(t){return e.get(t,!0)},e.set=function(e,t,o,r){o!==!0&&(r=o,o=!1),r=n(r?r:{});var u=e+"="+(o?t:encodeURIComponent(t))+r;document.cookie=u},e.setRaw=function(t,n,o){e.set(t,n,!0,o)},e.remove=function(t){e.set(t,"a",{expires:new Date})},e}); 2 | -------------------------------------------------------------------------------- /cms/templates/_layouts/error-page-layout.twig: -------------------------------------------------------------------------------- 1 | {# -- Layout template for error pages -- #} 2 | {# 3 | ┌─────────────────────────────────────────────────────────────────────────────┐ 4 | │ ┌─────────────────────────────────────────────────────────────────────────┐ │ 5 | │ │ │ │ 6 | │ │ │ │ 7 | │ │ │ │ 8 | │ │ content │ │ 9 | │ └─────────────────────────────────────────────────────────────────────────┘ │ 10 | │ ┌─────────────────────────────────────────────────────────────────────────┐ │ 11 | │ │ │ │ 12 | │ │ │ │ 13 | │ │ │ │ 14 | │ │ subContent │ │ 15 | │ └─────────────────────────────────────────────────────────────────────────┘ │ 16 | │ │ 17 | │ bodyHtml │ 18 | └─────────────────────────────────────────────────────────────────────────────┘ 19 | #} 20 | {% extends "_layouts/generic-page-layout.twig" %} 21 | 22 | {% block content %} 23 | {% endblock %} 24 | 25 | {% block subcontent %} 26 |
27 |
28 |
29 |
30 |

31 | {{ entry.errorHeadline }} 32 |

33 |

34 | {{ entry.errorText |nl2br }} 35 |

36 |
37 |
38 |
39 |
40 | 41 | {% include "episodes/_partials/_display_recent_episodes.twig" with { 42 | "showInfo": showInfo, 43 | } only %} 44 | {% endblock %} 45 | 46 | {# -- Any JavaScript that should be included before -- #} 47 | {% block bodyJs %} 48 | {{ craft.vite.script("src/js/modules/player.js") }} 49 | {{ craft.vite.script("src/js/modules/episodes.js") }} 50 | {% endblock bodyJs %} 51 | -------------------------------------------------------------------------------- /cms/templates/_layouts/global-variables.twig: -------------------------------------------------------------------------------- 1 | {# -- Root global variables that all templates inherit from -- #} 2 | {# -- This allows for defining site-wide Twig variables as needed -- #} 3 | {# 4 | ┌─────────────────────────────────────────────────────────────────────────────┐ 5 | │ │ 6 | │ │ 7 | │ │ 8 | │ htmlPage │ 9 | └─────────────────────────────────────────────────────────────────────────────┘ 10 | #} 11 | {% apply spaceless %} 12 | 13 | {# -- Prefetch & preconnect headers and links -- #} 14 | {% set prefetchUrls = [ 15 | alias("@assetsUrl"), 16 | alias("@cloudfrontUrl"), 17 | alias("@ptGoogleAnalyticsProxy"), 18 | alias("@transcodedEpisodes"), 19 | ] %} 20 | {# -- General global variables -- #} 21 | {% set baseUrl = alias('@cloudfrontUrl') ~ '/' %} 22 | {% set assetsUrl = alias('@assetsUrl') ~ '/' %} 23 | {% set backgroundUrl = "#{baseUrl}site/devmode-fm-light-bg-opaque.svg" %} 24 | {% set footerBackgroundUrl = "#{baseUrl}site/devmode-fm-dark-bg.svg" %} 25 | {% set gaTrackingId = getenv('GA_TRACKING_ID') %} 26 | 27 | {# -- Twig output from the render; this must be in a block -- #} 28 | {% block htmlPage %} 29 | {% endblock %} 30 | 31 | {% endapply %} 32 | -------------------------------------------------------------------------------- /cms/templates/_layouts/player-page-layout.twig: -------------------------------------------------------------------------------- 1 | {# -- Layout template for HTML pages -- #} 2 | {# 3 | ┌─────────────────────────────────────────────────────────────────────────────┐ 4 | │ ┌─────────────────────────────────────────────────────────────────────────┐ │ 5 | │ │ │ │ 6 | │ │ │ │ 7 | │ │ │ │ 8 | │ │ content │ │ 9 | │ └─────────────────────────────────────────────────────────────────────────┘ │ 10 | │ │ 11 | │ bodyHtml │ 12 | └─────────────────────────────────────────────────────────────────────────────┘ 13 | #} 14 | {% extends "_boilerplate/_layouts/base-html-layout.twig" %} 15 | 16 | {# -- Any CSS that should be included before -- #} 17 | {% block headCss %} 18 | {% include "_inline-css/site-fonts.css" %} 19 | {% endblock headCss %} 20 | 21 | {# -- Page body -- #} 22 | {% block bodyHtml %} 23 |
24 |
25 |
26 |
27 | {# -- Primary content block -- #} 28 | {% block content %} 29 | {% endblock %} 30 |
31 |
32 |
33 |
34 | {% endblock bodyHtml %} 35 | -------------------------------------------------------------------------------- /cms/templates/_partials/_meta-schema-radio-series.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # Add audio schema for the this episode as per: 3 | # https://schema.org/PodcastSeries 4 | # 5 | # @param showInfo the showInfo Global for the show 6 | #} 7 | 8 | {% from "_partials/macros.twig" import addPersonArray %} 9 | 10 | {# Merge in the additional properties to the PodcastSeries mainEntityOfPage #} 11 | {% set mainEntity = seomatic.jsonLd.get('mainEntityOfPage') %} 12 | {% do mainEntity.setAttributes({ 13 | 'genre': showInfo.showGenre, 14 | 'productionCompany': { 15 | 'id': '{seomatic.site.creator.genericUrl}#creator', 16 | }, 17 | }) %} 18 | 19 | {# Person array of the episode hosts #} 20 | {% do addPersonArray(mainEntity, 'actor', craft.users.group("hosts").all()) %} 21 | {# Person array of the episode directors #} 22 | {% do addPersonArray(mainEntity, 'director', craft.users.group("owners").all()) %} 23 | -------------------------------------------------------------------------------- /cms/templates/_partials/amp-info-footer.twig: -------------------------------------------------------------------------------- 1 | {% apply spaceless %} 2 | {% set hosts = craft.users.group("owners").all() %} 3 | {% endapply %} 4 |
25 | -------------------------------------------------------------------------------- /cms/templates/_partials/amp-info-header.twig: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /cms/templates/_partials/amp-inline-css.css: -------------------------------------------------------------------------------- 1 | .content-background { 2 | background-image: url("{{ backgroundUrl }}"); 3 | } 4 | 5 | .footer-background { 6 | background-image: url("{{ footerBackgroundUrl }}"); 7 | background-size: 600px; 8 | min-height: 18rem; 9 | } 10 | 11 | ul.nav-amp { 12 | color: #fff; 13 | overflow: hidden; 14 | transition: all 0.3s ease; 15 | list-style-type: none; 16 | padding: 1rem; 17 | margin: 0 auto; 18 | } 19 | 20 | ul.nav-amp li { 21 | padding-top: 1rem; 22 | } 23 | -------------------------------------------------------------------------------- /cms/templates/_partials/amp-navbar.twig: -------------------------------------------------------------------------------- 1 | 2 | 45 | 46 | -------------------------------------------------------------------------------- /cms/templates/_partials/amp-webmentions-facepile.twig: -------------------------------------------------------------------------------- 1 | {# -- Webmentions facepile -- #} 2 | {% if entry is defined and entry | length %} 3 | 29 | {% endif %} 30 | -------------------------------------------------------------------------------- /cms/templates/_partials/global-footer.twig: -------------------------------------------------------------------------------- 1 | {#-- Global footer --#} 2 | 3 | {#-- Browser fixes --#} 4 | 8 | -------------------------------------------------------------------------------- /cms/templates/_partials/info-footer.twig: -------------------------------------------------------------------------------- 1 | {% set backgroundUrl = "#{baseUrl}site/devmode-fm-dark-bg.svg" %} 2 | {% from "_partials/macros.twig" import displayCodeLines %} 3 | {% apply spaceless %} 4 | {% set hosts = craft.users.group("owners").all() %} 5 | {% endapply %} 6 | 28 | -------------------------------------------------------------------------------- /cms/templates/_partials/webmentions-facepile.twig: -------------------------------------------------------------------------------- 1 | {# -- Webmentions facepile -- #} 2 | {% if entry is defined and entry | length %} 3 | 29 | {% endif %} 30 | -------------------------------------------------------------------------------- /cms/templates/about/_partials/_meta-schema-faqpage.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # Add FAQPage schema for the this page as per: 3 | # https://schema.org/FAQPage 4 | # 5 | # @param faqs the FAQs matrix blocks 6 | # @param showInfo the showInfo Global for the show 7 | #} 8 | 9 | {% set faqsArray = [] %} 10 | {% for faq in faqs.all() %} 11 | {% set faqLinks = '' %} 12 | {% for link in faq.links %} 13 | {%- set linkHtml -%} 14 | {{ link.linkText }} 15 | {%- endset -%} 16 | {% set faqLinks = faqLinks ~ linkHtml ~ (loop.last ? '' : ', ') %} 17 | {% endfor %} 18 | {% set faqsArray = faqsArray | merge([seomatic.jsonLd.create({ 19 | 'type': 'Question', 20 | 'name': faq.question, 21 | 'acceptedAnswer': { 22 | 'type': 'Answer', 23 | 'text': (faq.answer ~ faqLinks), 24 | }, 25 | }, false)]) %} 26 | {% endfor %} 27 | 28 | {# Merge in the additional properties to the FAQpage mainEntityOfPage #} 29 | {% set mainEntity = seomatic.jsonLd.get('mainEntityOfPage') %} 30 | {% do mainEntity.setAttributes({ 31 | 'mainEntity': faqsArray, 32 | }) %} 33 | -------------------------------------------------------------------------------- /cms/templates/amp-index.twig: -------------------------------------------------------------------------------- 1 | {% extends "_layouts/amp-generic-page-layout.twig" %} 2 | 3 | {% if entry is not defined %} 4 | {% set entry = craft.entries({ 5 | "uri": "__home__", 6 | }).one() %} 7 | {% endif %} 8 | 9 | {% do seomatic.helper.loadMetadataForUri(entry.uri) %} 10 | {% do seomatic.script.container().include(false) %} 11 | 12 | {% block content %} 13 |
14 |
15 | {% for episode in craft.entries.section("episodes").limit(1).all() %} 16 |
17 | {% include "episodes/_partials/_amp_display_episode.twig" with { 18 | "episode": episode, 19 | "showInfo": showInfo, 20 | } only %} 21 |
22 | {% endfor %} 23 |
24 |
25 | {% endblock %} 26 | 27 | {% block subcontent %} 28 | {% include "episodes/_partials/_amp_display_recent_episodes.twig" with { 29 | "showInfo": showInfo, 30 | } only %} 31 | {% endblock %} 32 | 33 | {% block bodyJs %} 34 | {% endblock bodyJs %} 35 | -------------------------------------------------------------------------------- /cms/templates/calendar/_partials/_display_event_excerpt.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | {# -- Episode title -- #} 6 |
7 |

8 | {{ episode.title | typogrify(true) }} 9 |

10 |
11 | {# -- Episode number and date -- #} 12 |
13 | {{ "Episode " ~ episode.episodeNumber }} / {{ episode.postDate | date("Y.m.d") }} 14 |
15 |
16 | {# -- Episode summary -- #} 17 |
18 | {% if episode.episodeSummary | length %} 19 | {{ episode.episodeSummary | truncateOnWord(400) | typogrify }} 20 | {% endif %} 21 |
22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /cms/templates/episodes/_amp-entry.twig: -------------------------------------------------------------------------------- 1 | 2 | {% extends "_layouts/amp-generic-page-layout.twig" %} 3 | 4 | {% if entry is not defined %} 5 | {% set entrySlug = craft.app.request.getSegment(2) %} 6 | {% set entry = craft.entries({ 7 | "section": "episodes", 8 | "slug": entrySlug, 9 | }).one() %} 10 | {% endif %} 11 | 12 | {% do seomatic.helper.loadMetadataForUri(entry.uri) %} 13 | {% do seomatic.script.container().include(false) %} 14 | 15 | {% block content %} 16 |
17 |
18 |
19 | {% include "episodes/_partials/_amp_display_episode.twig" with { 20 | "episode": entry, 21 | "showInfo": showInfo, 22 | } only %} 23 |
24 |
25 |
26 | {# -- Webmentions facepile -- #} 27 |
28 |
29 |
30 | {% include "_partials/amp-webmentions-facepile.twig" with { 31 | "entry": entry, 32 | } only %} 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block subcontent %} 39 | 40 | {% include "episodes/_partials/_amp_display_recent_episodes.twig" with { 41 | "showInfo": showInfo, 42 | } only %} 43 | {% endblock %} 44 | 45 | {% block bodyJs %} 46 | {% endblock bodyJs %} 47 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_amp_display_episode_excerpt.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | {# -- Episode title -- #} 6 | 13 | {# -- Episode number and date -- #} 14 |
15 | {{ "Episode " ~ episode.episodeNumber }} / {{ episode.postDate |date("Y.m.d") }} 16 |
17 |
18 | {# -- Episode summary -- #} 19 |
20 | {{ episode.episodeSummary |truncateOnWord(400) |typogrify }} 21 |
22 | {# -- Episode tags -- #} 23 |
24 | {% for tag in episode.episodeTags.all() %} 25 | 26 | #{{ tag.title }} 27 | 28 | {% endfor %} 29 |
30 | {# -- Comments -- #} 31 | {% set commentsCount = disqusCount(episode.slug) | default(0) %} 32 | 40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_amp_display_recent_episodes.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

7 | Recent Episodes 8 |

9 |
10 |
11 |
12 | {% for episode in craft.entries.section("episodes").limit(null).all() %} 13 |
14 |
15 | {% include "episodes/_partials/_amp_display_episode_excerpt.twig" with { 16 | "episode": episode, 17 | "showInfo": showInfo, 18 | } only %} 19 |
20 |
21 | {% endfor %} 22 |
23 |
24 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_display_episode_excerpt.twig: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
6 | {# -- Episode title -- #} 7 | 14 | {# -- Episode number and date -- #} 15 |
16 | {{ "Episode " ~ episode.episodeNumber }} / {{ episode.postDate |date("Y.m.d") }} 17 |
18 |
19 | {# -- Episode summary -- #} 20 |
21 | {{ episode.episodeSummary |truncateOnWord(400) |typogrify }} 22 |
23 | {# -- Episode tags -- #} 24 |
25 | {% for tag in episode.episodeTags.all() %} 26 | 27 | #{{ tag.title }} 28 | 29 | {% endfor %} 30 |
31 | {# -- Comments -- #} 32 | {% set commentsCount = disqusCount(episode.slug) | default(0) %} 33 | 41 |
42 |
43 |
44 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_display_player.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 | {# -- Audio player -- #} 4 | {% set transAudioUrl = craft.transcoder.getAudioUrl(episode.episodeMedia.one(), { 5 | "audioBitRate": "128k", 6 | "audioSampleRate": 44100, 7 | "audioChannels": 1 8 | }) %} 9 | {% if transAudioUrl |length %} 10 | {# Disable Chartable tracking; it gets flagged by some ad blockers 11 | {% if not craft.app.config.general.devMode %} 12 | {% set transAudioUrl = transAudioUrl | replace('/^(http|https):/', '') %} 13 | {% set transAudioUrl = transAudioUrl | replace('//', '') %} 14 | {% set transAudioUrl = "https://chtbl.com/track/81493/#{transAudioUrl}" %} 15 | {% endif %} 16 | #} 17 | {% set fileInfo = craft.transcoder.getFileInfo(episode.episodeMedia.one(), true) %} 18 | {% if includeAudioMeta is defined and includeAudioMeta and fileInfo | length %} 19 | {% include "episodes/_partials/_meta-episode-custom.twig" with { 20 | "episode": episode, 21 | "fileInfo": fileInfo, 22 | "showInfo": showInfo, 23 | "audioUrl": transAudioUrl, 24 | } only %} 25 | {% endif %} 26 | {% set autoPlay = autoPlay ?? false %} 27 |
28 | 38 | 39 |
40 | {% endif %} 41 | {{ craft.vite.script("src/js/modules/player.js") }} 42 |
43 |
44 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_display_recent_episodes.twig: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |

7 | Recent Episodes 8 |

9 |
10 |
11 |
12 |
13 |
14 | 15 | 16 |
17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_display_transcript.twig: -------------------------------------------------------------------------------- 1 | {# @var \craft\elements\Asset transcript #} 2 | {# @var \craft\elements\User host #} 3 | 4 |
5 |
6 | {# -- Episode transcript -- #} 7 |
8 |
9 | 12 | 29 |
30 |
31 |
32 |
33 | 34 | 41 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_meta-episode-custom.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # Add custom meta information for the episode 3 | # 4 | # @param episode the episode Entry for the current page 5 | # @param fileInfo summary of the episode media file info as per: 6 | # https://github.com/nystudio107/craft-transcoder#getting-information-about-a-videoaudio-file 7 | # @param showInfo the showInfo Global for the show 8 | # @param audioUrl the URL to the audio for this episode, wrapped in the 9 | # Chartable.com tracking redirect 10 | #} 11 | 12 | {% include "episodes/_partials/_meta-og-audio.twig" with { 13 | "episode": episode, 14 | "fileInfo": fileInfo, 15 | "showInfo": showInfo, 16 | "audioUrl": audioUrl, 17 | } only %} 18 | 19 | {% include "episodes/_partials/_meta-schema-audio.twig" with { 20 | "episode": episode, 21 | "fileInfo": fileInfo, 22 | "showInfo": showInfo, 23 | "audioUrl": audioUrl, 24 | } only %} 25 | 26 | {% include "episodes/_partials/_meta-twitter-player-card.twig" with { 27 | "episode": episode, 28 | "fileInfo": fileInfo, 29 | "showInfo": showInfo, 30 | "audioUrl": audioUrl, 31 | } only %} 32 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_meta-og-audio.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # Add og:audio tags for the this episode as per: 3 | # http://ogp.me/#structured 4 | # 5 | # @param episode the episode Entry for the current page 6 | # @param fileInfo summary of the episode media file info as per: 7 | # https://github.com/nystudio107/craft-transcoder#getting-information-about-a-videoaudio-file 8 | # @param showInfo the showInfo Global for the show 9 | # @param audioUrl the URL to the audio for this episode, wrapped in the 10 | # Chartable.com tracking redirect 11 | #} 12 | 13 | {% do seomatic.meta.ogType('music.song') %} 14 | {% do seomatic.tag.create({ 15 | 'property': 'og:audio', 16 | 'content': audioUrl 17 | }) %} 18 | {% do seomatic.tag.create({ 19 | 'property': 'og:audio:type', 20 | 'content': 'audio/mpeg' 21 | }) %} 22 | {% do seomatic.tag.create({ 23 | 'property': 'og:audio:title', 24 | 'content': episode.title 25 | }) %} 26 | {% do seomatic.tag.create({ 27 | 'property': 'og:audio:artist', 28 | 'content': showInfo.showTitle 29 | }) %} 30 | {% do seomatic.tag.create({ 31 | 'property': 'og:audio:album', 32 | 'content': showInfo.showTitle 33 | }) %} 34 | -------------------------------------------------------------------------------- /cms/templates/episodes/_partials/_meta-twitter-player-card.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # Add twitter:player cards for this episode as per: 3 | # https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/player-card.html 4 | # 5 | # @param episode the episode Entry for the current page 6 | # @param fileInfo summary of the episode media file info as per: 7 | # https://github.com/nystudio107/craft-transcoder#getting-information-about-a-videoaudio-file 8 | # @param showInfo the showInfo Global for the show 9 | # @param audioUrl the URL to the audio for this episode, wrapped in the 10 | # Chartable.com tracking redirect 11 | #} 12 | 13 | {% do seomatic.meta.twitterCard('player') %} 14 | 15 | {# Create a scaled down image to match the width of the player #} 16 | {% set playerWidth = 400 %} 17 | {% set playerHeight = 150 %} 18 | {% set playerImage = showInfo.showImage.one().getUrl({ 19 | 'width': playerWidth, 20 | 'height': playerHeight, 21 | }) %} 22 | {% do seomatic.meta.setAttributes({ 23 | 'twitterImage': playerImage, 24 | 'twitterImageWidth': playerWidth, 25 | 'twitterImageHeight': playerHeight, 26 | }) %} 27 | 28 | {# Add in the twitter:player specific tags #} 29 | {% do seomatic.tag.create({ 30 | 'name': 'twitter:player', 31 | 'content': siteUrl("/player-card/#{episode.slug}") 32 | }) %} 33 | {% do seomatic.tag.create({ 34 | 'name': 'twitter:player:width', 35 | 'content': playerWidth 36 | }) %} 37 | {% do seomatic.tag.create({ 38 | 'name': 'twitter:player:height', 39 | 'content': playerHeight 40 | }) %} 41 | {% do seomatic.tag.create({ 42 | 'name': 'twitter:player:stream', 43 | 'content': audioUrl 44 | }) %} 45 | {% do seomatic.tag.create({ 46 | 'name': 'twitter:player:stream:content_type', 47 | 'content': 'audio/mpeg' 48 | }) %} 49 | -------------------------------------------------------------------------------- /cms/templates/episodes/amp-index.twig: -------------------------------------------------------------------------------- 1 | {% extends "_layouts/amp-generic-page-layout.twig" %} 2 | 3 | {% if entry is not defined %} 4 | {% set entry = craft.entries({ 5 | "uri": "episodes", 6 | }).one() %} 7 | {% endif %} 8 | 9 | {% do seomatic.helper.loadMetadataForUri(entry.uri) %} 10 | {% do seomatic.script.container().include(false) %} 11 | 12 | {% block content %} 13 | {% endblock %} 14 | 15 | {% block subcontent %} 16 | {% include "episodes/_partials/_amp_display_recent_episodes.twig" with { 17 | "showInfo": showInfo, 18 | } only %} 19 | {% endblock %} 20 | 21 | {% block bodyJs %} 22 | {% endblock bodyJs %} 23 | -------------------------------------------------------------------------------- /cms/templates/episodes/index.twig: -------------------------------------------------------------------------------- 1 | {% extends "_layouts/generic-page-layout.twig" %} 2 | 3 | {% set includeAudioMeta = false %} 4 | 5 | {% block headLinks %} 6 | {{ parent() }} 7 | 8 | {% endblock headLinks %} 9 | 10 | {% block content %} 11 | {% include "_partials/_meta-schema-radio-series.twig" with { 12 | "showInfo": showInfo, 13 | } only %} 14 | {% endblock %} 15 | 16 | {% block subcontent %} 17 | {% include "episodes/_partials/_display_recent_episodes.twig" with { 18 | "showInfo": showInfo, 19 | } only %} 20 | {% endblock %} 21 | 22 | {# -- Any JavaScript that should be included before -- #} 23 | {% block bodyJs %} 24 | {{ craft.vite.script("src/js/modules/episodes.js") }} 25 | {% endblock bodyJs %} 26 | -------------------------------------------------------------------------------- /cms/templates/errors/404.twig: -------------------------------------------------------------------------------- 1 | {% set entry = craft.entries.section("notFound").limit(1).one() %} 2 | 3 | {% extends "_layouts/error-page-layout.twig" %} 4 | -------------------------------------------------------------------------------- /cms/templates/errors/503.twig: -------------------------------------------------------------------------------- 1 | {% set entry = craft.entries.section("serviceUnavailable").limit(1).one() %} 2 | 3 | {% extends "_layouts/error-page-layout.twig" %} 4 | -------------------------------------------------------------------------------- /cms/templates/errors/error.twig: -------------------------------------------------------------------------------- 1 | {% set entry = craft.entries.section("genericError").limit(1).one() %} 2 | 3 | {% extends "_layouts/error-page-layout.twig" %} 4 | -------------------------------------------------------------------------------- /cms/templates/errors/offline.twig: -------------------------------------------------------------------------------- 1 | {% set entry = craft.entries.section("siteOffline").limit(1).one() %} 2 | 3 | {% extends "_layouts/error-page-layout.twig" %} 4 | -------------------------------------------------------------------------------- /cms/templates/index.twig: -------------------------------------------------------------------------------- 1 | {% extends "_layouts/generic-page-layout.twig" %} 2 | 3 | {% set includeAudioMeta = false %} 4 | 5 | {% block headLinks %} 6 | {{ parent() }} 7 | 8 | {% endblock headLinks %} 9 | 10 | {% block content %} 11 | {% include "_partials/_meta-schema-radio-series.twig" with { 12 | "showInfo": showInfo, 13 | } only %} 14 |
15 |
16 | {% for episode in craft.entries.section("episodes").limit(1).all() %} 17 |
18 | {% include "episodes/_partials/_display_episode.twig" with { 19 | "episode": episode, 20 | "showInfo": showInfo, 21 | "includeAudioMeta": includeAudioMeta, 22 | "autoPlay": false, 23 | } only %} 24 |
25 | {% endfor %} 26 |
27 |
28 | {% endblock %} 29 | 30 | {% block subcontent %} 31 | {% include "episodes/_partials/_display_recent_episodes.twig" with { 32 | "showInfo": showInfo, 33 | } only %} 34 | {% endblock %} 35 | 36 | {# -- Any JavaScript that should be included before -- #} 37 | {% block bodyJs %} 38 | {{ craft.vite.script("src/js/modules/player.js") }} 39 | {{ craft.vite.script("src/js/modules/episodes.js") }} 40 | {% endblock bodyJs %} 41 | -------------------------------------------------------------------------------- /cms/templates/player-card.twig: -------------------------------------------------------------------------------- 1 | {% extends "_layouts/player-page-layout.twig" %} 2 | 3 | {% set includeAudioMeta = false %} 4 | 5 | {% if entry is not defined %} 6 | {% set entrySlug = craft.app.request.getSegment(2) %} 7 | {% set entry = craft.entries({ 8 | "section": "episodes", 9 | "slug": entrySlug, 10 | }).one() %} 11 | {% endif %} 12 | 13 | {% block content %} 14 |
15 |
16 |
17 | {% include "episodes/_partials/_display_player.twig" with { 18 | "episode": entry, 19 | "showInfo": showInfo, 20 | "includeAudioMeta": includeAudioMeta, 21 | "autoPlay": true, 22 | } only %} 23 |
24 |
25 |
26 | {% endblock %} 27 | 28 | {# -- Any JavaScript that should be included before -- #} 29 | {% block bodyJs %} 30 | {{ craft.vite.script("src/js/modules/player.js") }} 31 | {% endblock bodyJs %} 32 | -------------------------------------------------------------------------------- /cms/web/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/cms/web/.gitkeep -------------------------------------------------------------------------------- /cms/web/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | 4 | # Send would-be 404 requests to Craft 5 | RewriteCond %{REQUEST_FILENAME} !-f 6 | RewriteCond %{REQUEST_FILENAME} !-d 7 | RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC] 8 | RewriteRule (.+) index.php?p=$1 [QSA,L] 9 | 10 | -------------------------------------------------------------------------------- /cms/web/img/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/cms/web/img/.gitkeep -------------------------------------------------------------------------------- /cms/web/img/devmodefm-social-media.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/cms/web/img/devmodefm-social-media.png -------------------------------------------------------------------------------- /cms/web/img/favicon_src.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/cms/web/img/favicon_src.png -------------------------------------------------------------------------------- /cms/web/index.php: -------------------------------------------------------------------------------- 1 | run(); 13 | -------------------------------------------------------------------------------- /cms/web/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /db-seed/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | -------------------------------------------------------------------------------- /db-seed/db_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | POSTGRES_DB_SEED_DIR="dbs" 3 | POSTGRES_DATABASES_ARRAY=( $POSTGRES_DATABASES ) 4 | 5 | # Iterate through the databases we need to create & seed 6 | for POSTGRES_DB in "${POSTGRES_DATABASES_ARRAY[@]}" 7 | do 8 | # Define the client command used 9 | pgsql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" ) 10 | echo "### Creating user \`$POSTGRES_USER\`" 11 | echo "CREATE USER $POSTGRES_DB ;" | "${pgsql[@]}" 12 | echo "### Creating database \`$POSTGRES_DB\`" 13 | echo "CREATE DATABASE $POSTGRES_DB ;" | "${pgsql[@]}" 14 | echo "### Granting ALL on database \`$POSTGRES_DB\`" 15 | echo "GRANT ALL PRIVILEGES ON DATABASE $POSTGRES_DB TO $POSTGRES_DB ;" | "${pgsql[@]}" 16 | # Add the database name to the command 17 | pgsql+=( "$POSTGRES_DB" ) 18 | DB_SEED_PATH="/docker-entrypoint-initdb.d/$POSTGRES_DB_SEED_DIR/$POSTGRES_DB" 19 | if [ -f "$DB_SEED_PATH.sql" ]; then 20 | echo "### Seeding database with \`$DB_SEED_PATH.sql\`" 21 | cat "$DB_SEED_PATH.sql" | "${pgsql[@]}" >/dev/null 22 | echo "### \`$POSTGRES_DB\` database seeded" 23 | fi 24 | if [ -f "$DB_SEED_PATH.sql.gz" ]; then 25 | echo "### Seeding database with \`$DB_SEED_PATH.sql.gz\`" 26 | zcat "$DB_SEED_PATH.sql.gz" | "${pgsql[@]}" >/dev/null 27 | echo "### \`$POSTGRES_DB\` database seeded" 28 | fi 29 | done 30 | -------------------------------------------------------------------------------- /db-seed/dbs/project.sql.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nystudio107/devmode/8339b0ebd0c1c0c6806a727349ab58e268393e7f/db-seed/dbs/project.sql.gz -------------------------------------------------------------------------------- /scripts/common/common_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Common DB 4 | # 5 | # Shared script to set various database-related variables 6 | # 7 | # @author nystudio107 8 | # @copyright Copyright (c) 2020 nystudio107 9 | # @link https://nystudio107.com/ 10 | # @license MIT 11 | 12 | # Tables to exclude from the db dump 13 | EXCLUDED_DB_TABLES=( 14 | "assetindexdata" 15 | "assettransformindex" 16 | "cache" 17 | "sessions" 18 | "templatecaches" 19 | "templatecachecriteria" 20 | "templatecacheelements" 21 | "templatecachequeries" 22 | ) 23 | 24 | TMP_DB_DUMP_CREDS_PATH="/tmp/craftscripts.creds" 25 | 26 | # -- LOCAL settings -- hard-coded for Docker 27 | 28 | # Local database constants; default port for mysql is 3306, default port for postgres is 5432 29 | LOCAL_DB_NAME="project" 30 | LOCAL_DB_PASSWORD="project" 31 | LOCAL_DB_USER="project" 32 | LOCAL_DB_HOST="localhost" 33 | LOCAL_DB_PORT="5432" 34 | LOCAL_DB_SCHEMA="public" 35 | 36 | # The `mysql` and `mysqldump` commands to run locally 37 | LOCAL_MYSQL_CMD="mysql" 38 | LOCAL_MYSQLDUMP_CMD="mysqldump" 39 | 40 | # The `psql` and `pg_dump` commands to run locally 41 | LOCAL_PSQL_CMD="psql" 42 | LOCAL_PG_DUMP_CMD="pg_dump" 43 | -------------------------------------------------------------------------------- /scripts/common/common_env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Common Env 4 | # 5 | # Shared script to set various environment-related variables 6 | # 7 | # @author nystudio107 8 | # @copyright Copyright (c) 2020 nystudio107 9 | # @link https://nystudio107.com/ 10 | # @license MIT 11 | 12 | # Commands to output database dumps, using gunzip -c instead of zcat for MacOS X compatibility 13 | DB_ZCAT_CMD="gunzip -c" 14 | DB_CAT_CMD="cat" 15 | -------------------------------------------------------------------------------- /scripts/common/common_pgsql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Common pgsql 4 | # 5 | # Shared script to set various database-related variables 6 | # 7 | # @author nystudio107 8 | # @copyright Copyright (c) 2020 nystudio107 9 | # @link https://nystudio107.com/ 10 | # @license MIT 11 | 12 | LOCAL_IGNORED_DB_TABLES_STRING="" 13 | REMOTE_IGNORED_DB_TABLES_STRING="" 14 | for TABLE in "${EXCLUDED_DB_TABLES[@]}" 15 | do 16 | LOCAL_IGNORED_DB_TABLES_STRING+="--exclude-table-data=${LOCAL_DB_SCHEMA}.${GLOBAL_DB_TABLE_PREFIX}${TABLE} " 17 | REMOTE_IGNORED_DB_TABLES_STRING+="--exclude-table-data=${REMOTE_DB_SCHEMA}.${GLOBAL_DB_TABLE_PREFIX}${TABLE} " 18 | done 19 | 20 | # Additional arguments for pg_dump 21 | PG_DUMP_ADDITIONAL_ARGS="" 22 | PG_DUMP_ADDITIONAL_ARGS+="--no-password " 23 | PG_DUMP_ADDITIONAL_ARGS+="--if-exists " 24 | PG_DUMP_ADDITIONAL_ARGS+="--clean " 25 | PG_DUMP_ADDITIONAL_ARGS+="--no-owner " 26 | PG_DUMP_ADDITIONAL_ARGS+="--no-privileges " 27 | PG_DUMP_ADDITIONAL_ARGS+="--no-acl " 28 | 29 | # Arguments to dump just the data 30 | PG_DUMP_ARGS="" 31 | PG_DUMP_ARGS+=$PG_DUMP_ADDITIONAL_ARGS 32 | 33 | # Build the remote psql credentials 34 | REMOTE_DB_CREDS="" 35 | if [[ -n "${REMOTE_DB_HOST}" ]] ; then 36 | REMOTE_DB_CREDS+="--host=${REMOTE_DB_HOST} " 37 | fi 38 | if [[ -n "${REMOTE_DB_PORT}" ]] ; then 39 | REMOTE_DB_CREDS+="--port=${REMOTE_DB_PORT} " 40 | fi 41 | if [[ -n "${REMOTE_DB_NAME}" ]] ; then 42 | REMOTE_DB_CREDS+="--dbname=${REMOTE_DB_NAME} " 43 | fi 44 | if [[ -n "${REMOTE_DB_USER}" ]] ; then 45 | REMOTE_DB_CREDS+="--username=${REMOTE_DB_USER} " 46 | fi 47 | 48 | # Build the local psql credentials 49 | LOCAL_DB_CREDS="" 50 | if [[ -n "${LOCAL_DB_HOST}" ]] ; then 51 | LOCAL_DB_CREDS+="--host=${LOCAL_DB_HOST} " 52 | fi 53 | if [[ -n "${LOCAL_DB_PORT}" ]] ; then 54 | LOCAL_DB_CREDS+="--port=${LOCAL_DB_PORT} " 55 | fi 56 | if [[ -n "${LOCAL_DB_NAME}" ]] ; then 57 | LOCAL_DB_CREDS+="--dbname=${LOCAL_DB_NAME} " 58 | fi 59 | if [[ -n "${LOCAL_DB_USER}" ]] ; then 60 | LOCAL_DB_CREDS+="--username=${LOCAL_DB_USER} " 61 | fi 62 | -------------------------------------------------------------------------------- /scripts/common/defaults.sh: -------------------------------------------------------------------------------- 1 | #@IgnoreInspection BashAddShebang 2 | # Craft Scripts Defaults 3 | # 4 | # Default settings for Craft scripts 5 | # 6 | # @author nystudio107 7 | # @copyright Copyright (c) 2020 nystudio107 8 | # @link https://nystudio107.com/ 9 | # @license MIT 10 | 11 | # -- GLOBAL settings -- 12 | 13 | # The database driver for this Craft install ('mysql' or 'pgsql') 14 | GLOBAL_DB_DRIVER="mysql" 15 | 16 | # -- LOCAL settings -- 17 | 18 | # Local database constants; default port for mysql is 3306, default port for postgres is 5432 19 | LOCAL_DB_NAME="REPLACE_ME" 20 | LOCAL_DB_PASSWORD="REPLACE_ME" 21 | LOCAL_DB_USER="REPLACE_ME" 22 | LOCAL_DB_HOST="localhost" 23 | LOCAL_DB_PORT="3306" 24 | LOCAL_DB_SCHEMA="public" 25 | 26 | # If you are using mysql 5.6.10 or later and you have `login-path` setup as per: 27 | # https://opensourcedbms.com/dbms/passwordless-authentication-using-mysql_config_editor-with-mysql-5-6/ 28 | # you can use it instead of the above LOCAL_DB_* constants; otherwise leave this blank 29 | LOCAL_DB_LOGIN_PATH="" 30 | 31 | # The `mysql` and `mysqldump` commands to run locally 32 | LOCAL_MYSQL_CMD="mysql" 33 | LOCAL_MYSQLDUMP_CMD="mysqldump" 34 | 35 | # The `psql` and `pg_dump` commands to run locally 36 | LOCAL_PSQL_CMD="psql" 37 | LOCAL_PG_DUMP_CMD="pg_dump" 38 | 39 | # -- REMOTE settings -- 40 | 41 | # Remote ssh credentials, user@domain.com and Remote SSH Port 42 | REMOTE_SSH_LOGIN="REPLACE_ME" 43 | REMOTE_SSH_PORT="22" 44 | 45 | # Should we connect to the remote database server via ssh? 46 | REMOTE_DB_USING_SSH="yes" 47 | 48 | # Remote database constants; default port for mysql is 3306, default port for postgres is 5432 49 | REMOTE_DB_NAME="REPLACE_ME" 50 | REMOTE_DB_PASSWORD="REPLACE_ME" 51 | REMOTE_DB_USER="REPLACE_ME" 52 | REMOTE_DB_HOST="localhost" 53 | REMOTE_DB_PORT="3306" 54 | REMOTE_DB_SCHEMA="public" 55 | 56 | # If you are using mysql 5.6.10 or later and you have `login-path` setup as per: 57 | # https://opensourcedbms.com/dbms/passwordless-authentication-using-mysql_config_editor-with-mysql-5-6/ 58 | # you can use it instead of the above REMOTE_DB_* constants; otherwise leave this blank 59 | REMOTE_DB_LOGIN_PATH="" 60 | 61 | # The `mysql` and `mysqldump` commands to run remotely 62 | REMOTE_MYSQL_CMD="mysql" 63 | REMOTE_MYSQLDUMP_CMD="mysqldump" 64 | 65 | # The `psql` and `pg_dump` commands to run remotely 66 | REMOTE_PSQL_CMD="psql" 67 | REMOTE_PG_DUMP_CMD="pg_dump" 68 | -------------------------------------------------------------------------------- /scripts/example.env.sh: -------------------------------------------------------------------------------- 1 | # Craft 3 Scripts Environment 2 | # 3 | # Local environmental config for nystudio107 Craft scripts 4 | # 5 | # @author nystudio107 6 | # @copyright Copyright (c) 2020 nystudio107 7 | # @link https://nystudio107.com/ 8 | # @license MIT 9 | # 10 | # This file should be renamed to '.env.sh' and it should reside in the 11 | # `scripts` directory. Add '.env.sh' to your .gitignore. 12 | 13 | # -- GLOBAL settings -- 14 | 15 | # The database driver for this Craft install ('mysql' or 'pgsql') 16 | GLOBAL_DB_DRIVER="pgsql" 17 | 18 | # -- LOCAL settings -- 19 | 20 | LOCAL_DB_CONTAINER="devmode_postgres_1" 21 | LOCAL_BUILDCHAIN_CONTAINER="devmode_webpack_1" 22 | 23 | # -- REMOTE settings -- 24 | 25 | # Remote ssh credentials, user@domain.com and Remote SSH Port 26 | REMOTE_SSH_LOGIN="forge@devmode.fm" 27 | REMOTE_SSH_PORT="22" 28 | 29 | # Should we connect to the remote database server via ssh? 30 | REMOTE_DB_USING_SSH="yes" 31 | 32 | # Remote database constants; default port for mysql is 3306, default port for postgres is 5432 33 | REMOTE_DB_NAME="devmode" 34 | REMOTE_DB_PASSWORD="REPLACE_ME" 35 | REMOTE_DB_USER="devmode" 36 | REMOTE_DB_HOST="localhost" 37 | REMOTE_DB_PORT="5432" 38 | REMOTE_DB_SCHEMA="public" 39 | 40 | # If you are using mysql 5.6.10 or later and you have `login-path` setup as per: 41 | # https://opensourcedbms.com/dbms/passwordless-authentication-using-mysql_config_editor-with-mysql-5-6/ 42 | # you can use it instead of the above REMOTE_DB_* constants; otherwise leave this blank 43 | REMOTE_DB_LOGIN_PATH="" 44 | 45 | # The `mysql` and `mysqldump` commands to run remotely 46 | REMOTE_MYSQL_CMD="mysql" 47 | REMOTE_MYSQLDUMP_CMD="mysqldump" 48 | 49 | # The `psql` and `pg_dump` commands to run remotely 50 | REMOTE_PSQL_CMD="psql" 51 | REMOTE_PG_DUMP_CMD="pg_dump" 52 | --------------------------------------------------------------------------------