elements that wrap
elements. This allows us to properly style images
-# separately from , e.g. to give them different widths.
-
-require 'kramdown/converter/html'
-
-BLANK_RE = /\A[[:space:]]*\z/
-
-module StandaloneImages
- def isImageElement(ele)
- return ele.type == :img || (ele.type == :html_element && ele.value == "img")
- end
- def convert_p(el, indent)
- return super unless el.children.any? {|child| isImageElement(child) } || el.children.all? { |child| child.type == :a }
- # remove empty text elements that might be sandwiched between images
- els = el.children.select { |child| child.type != :text || !BLANK_RE.match?(child.value) }
- els = els.map { |child|
- if child.children.size == 1 && isImageElement(child.children.first)
- if child.attr['class'].nil?
- child.attr['class'] = 'img-container'
- else
- child.attr['class'] = child.attr['class'] + ' img-container'
- end
- end
- convert(child, indent)
- }
- return els.join('')
- end
-end
-
-Kramdown::Converter::Html.prepend StandaloneImages
\ No newline at end of file
diff --git a/_plugins/unwrap-img/unwrap-img.gemspec b/_plugins/unwrap-img/unwrap-img.gemspec
deleted file mode 100644
index dcece94..0000000
--- a/_plugins/unwrap-img/unwrap-img.gemspec
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-Gem::Specification.new do |spec|
- spec.name = "unwrap-img"
- spec.version = "0.1.0"
- spec.authors = ["Quincy Morgan"]
- spec.email = ["2046746+quincylvania@users.noreply.github.com"]
-
- spec.summary = "Unwrap Kramdown
elements from
elements."
- spec.homepage = "https://github.com/osmus/dogwood"
- spec.license = "MIT"
-
- spec.files = Dir["lib/**/*"]
-
- spec.add_runtime_dependency "jekyll", "~> 4.3"
-end
diff --git a/_redirects/trees.md b/_redirects/trees.md
deleted file mode 100644
index c25548b..0000000
--- a/_redirects/trees.md
+++ /dev/null
@@ -1,3 +0,0 @@
----
-redirect: /plants/
----
\ No newline at end of file
diff --git a/_sass/dogwood/_base.scss b/_sass/dogwood/_base.scss
deleted file mode 100644
index b39101b..0000000
--- a/_sass/dogwood/_base.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Reset ♥
- http://meyerweb.com/eric/tools/css/reset/
- v2.0 | 20110126
- License: none (public domain)
-------------------------------------------------------- */
-html, body, div, span, applet, object, iframe,
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,
-a, abbr, acronym, address, big, cite, code,
-del, dfn, em, img, ins, kbd, q, s, samp,
-small, strike, strong, sub, sup, tt, var,
-b, u, i, center,
-dl, dt, dd, ol, ul, li,
-fieldset, form, label, legend,
-table, caption, tbody, tfoot, thead, tr, th, td,
-article, aside, canvas, details, embed,
-figure, figcaption, footer, header, hgroup,
-menu, nav, output, ruby, section, summary,
-time, mark, audio, video {
- margin:0;
- padding:0;
- border:0;
- font-size:100%;
- font:inherit;
- vertical-align:baseline;
- }
-/* HTML5 display-role reset for older browsers */
-article, aside, details, figcaption, figure,
-footer, header, hgroup, menu, nav, section {
- display:block;
-}
-body { line-height:1; }
-ol, ul { list-style:none; }
-blockquote, q { quotes:none; }
-blockquote:before, blockquote:after,
-q:before, q:after { content:''; content:none; }
-/* tables still need 'cellspacing="0"' in the markup */
-table { border-collapse: collapse; border-spacing:0; }
-/* remember to define focus styles. Hee Haw */
-:focus { outline:0; }
-
-*, *:after, *:before {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
\ No newline at end of file
diff --git a/_sass/dogwood/_layout.scss b/_sass/dogwood/_layout.scss
deleted file mode 100644
index cb3eee2..0000000
--- a/_sass/dogwood/_layout.scss
+++ /dev/null
@@ -1,1599 +0,0 @@
-@use 'sass:color';
-
-/* Inline Elements & Typography
-------------------------------------------------------- */
-body {
- background-color: $background-color;
-}
-
-body,
-input,
-textarea {
- color: $text-color;
- font-size: $body-text-size;
- line-height: 1.6667;
- font-family: $sans-serif-font;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- font-variant-numeric: lining-nums;
-}
-
-h1, h2, h3, h4, h5, h6 {
- font-family: $serif-font;
- margin: 0;
- margin-bottom: $sp*0.5;
- font-weight: 600;
- line-height: 1.3;
-}
-
-h1 {
- font-weight: 700;
- font-size: 32px;
-}
-
-h2 {
- font-size: 26px;
-}
-
-h3 {
- font-size: 22px;
-}
-
-h4, h5 {
- font-size: 18px;
-}
-
-/* Links */
-a {
- color: $primary-color;
- text-decoration:none;
-}
-a:visited {
- color: $primary-color;
-}
-a:hover, a:active {
- color: lighten($primary-color, 10%);
-
- &:not(.button) {
- text-decoration: underline;
- }
-}
-
-.dark {
- background-color: $dark-background-color;
- color: white;
- a {
- color: $primary-color-alt;
-
- &:hover, &:active {
- color: lighten($primary-color-alt, 20%);
- }
- }
- hr {
- background: $dark-grid-color;
- }
-}
-
-abbr {
- border-bottom:1px dotted #000;
- cursor:help;
-}
-
-address { font-style:italic;}
-small { font-size:12px; line-height: 1.5;}
-strong, b { font-weight:700;}
-em, i { font-style:italic;}
-
-hr {
- margin: 0 0 20px;
- border: 0;
- height: 1px;
- background: $alpha-grid-color;
-}
-
-/* Block Quotes */
-blockquote, q {
- quotes:none;
- font-style:italic;
- padding-left:20px;
- border-left: 10px solid #e8e8e8;
-
- &.pullquote > *:not(cite) {
- font-size: 22px;
- }
-}
-
-blockquote:before,
-blockquote:after,
-q:before,
-q:after {
- content:'';
-}
-
-/* Code Blocks & Pre */
-code,
-pre {
- padding: 5px 4px;
- font-family: Menlo, Bitstream Vera Sans Mono, Monaco, Consolas, monospace;
- font-size: 12px;
- border-radius: 3px;
-}
-code {
- padding:5px;
- background: rgba(128,128,128,0.07);
- border: 1px solid $grid-color;
-}
-pre {
- display:block;
- padding:10px;
- word-break:break-all;
- word-wrap:break-word;
- white-space:pre;
- white-space:pre-wrap;
- background:#f8f8f8;
- border:1px solid #ddd;
- border-radius:3px;
-}
-pre code {
- padding:0;
- color:inherit;
- background-color:transparent;
- border:0;
-}
-.pre-scrollable {
- max-height:300px;
- overflow-y:scroll;
-}
-
-/* sub/superscripts */
-sup,
-sub {
- height:0;
- line-height:1;
- vertical-align:baseline;
- _vertical-align:bottom;
- position:relative;
- font-size:75%;
-}
-sup {
- bottom:1em;
-}
-
-label {
- display: block;
- font-weight: 600;
- font-size: 0.9em;
- cursor: pointer;
-}
-select,
-textarea,
-input[type=text],
-input[type=email] {
- display: inline-block;
- width: 500px;
- max-width: 100%;
- vertical-align: middle;
- padding: 4px 8px;
- border-radius: 3px;
- background-color:#fff;
- border:1px solid $grid-color;
-}
-textarea:focus,
-input[type=text]:focus,
-input[type=email]:focus {
- border-color: #70a177;
-}
-
-textarea {
- height:200px;
- max-width:none;
-}
-
-table {
- width:100%;
- background-color:transparent;
- border-collapse:collapse;
- border-spacing:0;
- table-layout:fixed;
-}
-th, td {
- padding: 4px 4px;
- text-align: left;
- vertical-align: top;
- border-bottom: 1px solid $grid-color;
-}
-tr:first-child {
- > th, > td {
- border-top: 1px solid $grid-color;
- }
-}
-th {
- font-weight:bold;
-}
-thead th {
- vertical-align:bottom;
- color:#57594D;
-}
-
-.iconsvg {
- fill: currentColor;
- display: inline-block;
- vertical-align: middle;
- width: 0.8em;
- height: 0.8em;
-}
-
-.iconsvg.pre-text {
- margin-right: 0.2em;
-}
-
-/* Layout
-------------------------------------------------------- */
-.container {
- position: relative;
- width: 100%;
- max-width: $container-width;
- margin: 0 auto;
- padding-right: $container-padding;
- padding-left: $container-padding;
-
- .inner-container {
- width: 100%;
- max-width: 900px;
- margin: 0 auto;
- }
-
- &.stretch {
- @media only screen and (max-width: $container-width) {
- padding: 0;
- .cover-image {
- border-left: 0;
- border-right: 0;
- }
- }
- }
-}
-.layout-post:not(.has-image) article.content{
- padding-top: 0;
-}
-.layout-post.has-image article.content {
- @media only screen and (max-width: $container-width) {
- padding-top: 0;
- .cover-image {
- border-top: 0;
- }
- }
-}
-
-form {
- padding: $sp;
- border: 1px solid #cfead3;
- background: #f3fff5;
- border-radius: 0 0 8px 8px;
- border-top-width: 4px;
- display: flex;
- flex-direction: column;
- align-items: baseline;
-
- > *:not(label):not(input[type='submit']) {
- margin-bottom: $sp*0.5;
- }
-
- input[type=submit] {
- padding: 10px 30px;
- margin-top: $sp*0.5;
- }
-}
-
-.bordered {
- border: 1px solid $grid-color;
-}
-
-/* Buttons
-------------------------------------------------------- */
-button, a.button, input[type=submit] {
- cursor: pointer;
- display: inline-block;
- font-weight: 600;
- text-align: center;
- -webkit-backdrop-filter: blur(10px);
- backdrop-filter: blur(10px);
- border: 0;
- padding: 2px 8px;
- border-radius: 6px;
-
- &:hover {
- filter: brightness(1.1);
- }
-
- &.bordered {
- border: 1px solid $primary-color;
- font-size: 0.95em;
-
- &:hover {
- background: rgba(0, 0, 0, 0.05);
- }
- }
- &.large {
- padding: 10px 20px;
- }
- &.wide {
- padding: 4px 24px;
- }
- &.white {
- border-color: white;
- color: white;
- &:hover {
- background: rgba(255, 255, 255, 0.1);
- }
- }
-
- &.prominent {
- background-color: $primary-color;
- color: white;
- &:hover {
- border-color: $primary-color-alt;
- background: $primary-color-alt;
- }
- }
-
- &.external:after {
- content: " ";
- background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%20fill%3D%22%23fff%22%3E%3C!--!%20Font%20Awesome%20Free%206.4.2%20by%20%40fontawesome%20-%20https%3A%2F%2Ffontawesome.com%20License%20-%20https%3A%2F%2Ffontawesome.com%2Flicense%20(Commercial%20License)%20Copyright%202023%20Fonticons%2C%20Inc.%20--%3E%3Cpath%20d%3D%22M320%200c-17.7%200-32%2014.3-32%2032s14.3%2032%2032%2032h82.7L201.4%20265.4c-12.5%2012.5-12.5%2032.8%200%2045.3s32.8%2012.5%2045.3%200L448%20109.3V192c0%2017.7%2014.3%2032%2032%2032s32-14.3%2032-32V32c0-17.7-14.3-32-32-32H320zM80%2032C35.8%2032%200%2067.8%200%20112V432c0%2044.2%2035.8%2080%2080%2080H400c44.2%200%2080-35.8%2080-80V320c0-17.7-14.3-32-32-32s-32%2014.3-32%2032V432c0%208.8-7.2%2016-16%2016H80c-8.8%200-16-7.2-16-16V112c0-8.8%207.2-16%2016-16H192c17.7%200%2032-14.3%2032-32s-14.3-32-32-32H80z%22%2F%3E%3C%2Fsvg%3E');
- background-repeat: no-repeat;
- display: inline-block;
- height: 0.8em;
- width: 0.8em;
- margin-left: 0.3em;
- }
-}
-
-.site-wordmark {
- display: flex;
- align-items: center;
- font-family: $serif-font;
- font-weight: bold;
- font-size: 21px;
- white-space: nowrap;
-
- .logo {
- height: 30px;
- margin-right: $sp*0.25;
- position: relative;
- top: 2px;
- }
-
- .text {
- color: inherit;
- }
-}
-
-
-/* Header
-------------------------------------------------------- */
-.topbar {
- position: fixed;
- top: 0;
- border-top: 5px solid $primary-color;
- z-index: 10000;
- background: $background-color;
- width: 100%;
- height: $topbar-height;
- border-bottom: 1px solid $grid-color;
-
- .site-wordmark {
- color: inherit;
- }
-
- .container {
- display: flex;
- justify-content: space-between;
- height: 100%;
- }
-
- @media only screen and (max-width: $sections-width) {
- position: relative;
- height: $topbar-height*1.8;
- .container {
- flex-direction: column;
- align-items: center;
- padding-top: $sp*0.33333;
- }
- }
-}
-
-.layout-body {
- background: $background-color;
- position: relative;
- margin-top: $topbar-height;
-
- min-height: calc(100vh - $topbar-height - $footer-min-height);
-
- @media only screen and (max-width: $sections-width) {
- margin-top: 0;
- }
-}
-
-ul.headernav {
- display: flex;
- flex-flow: row nowrap;
- align-items: center;
- height: 100%;
-
- > li {
- flex: 0 1 100%;
- font-size: 16px;
- font-weight: 600;
- white-space: nowrap;
- height: 100%;
-
- display: flex;
- align-items: center;
- position: relative;
-
- &:last-child {
- margin-left: $sp*0.5;
- }
-
- a {
- display: flex;
- align-items: center;
- }
-
- > a:not(.bordered) {
- padding: 0 min($sp, 1.5vw);
- color: $text-color;
- height: 100%;
- }
-
- ul.submenu {
- display: none;
- position: absolute;
- top: 100%;
- left: calc(min($sp, 1.5vw) - $sp*0.5);
- background: white;
- border: 1px solid $grid-color;
- border-radius: 5px;
- border-top-left-radius: 0;
- box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
-
- &::before {
- content: " ";
- background: white;
- position: absolute;
- left: 0;
- top: -1px;
- height: 1px;
- width: 80px;
- }
-
- a {
- height: 100%;
- width: 100%;
- padding: $sp*0.25 $sp*0.5 $sp*0.5 $sp*0.5;
- color: inherit;
- font-weight: 400;
- line-height: 1em;
- }
- }
- /* don't show hover menu on touch taps */
- @media (hover: hover) {
- &:hover {
- ul.submenu {
- display: block;
- }
- }
- }
- }
-}
-
-body:not(.layout-post):not(.layout-session) {
- .pagenav a {
- color: inherit;
- }
-}
-
-.breadcrumbs, .pagenav {
- width: 100%;
- z-index: 1000;
-}
-.breadcrumbs, .pagenav ul {
- font-size: 16px;
- font-weight: 600;
-}
-
-.breadcrumbs {
- margin-bottom: $sp;
- &:empty {
- display: none;
- }
- .iconsvg {
- margin-top: -2px;
- }
- a {
- color: inherit;
- }
-}
-
-.pagenav {
- display: flex;
- align-items: baseline;
- justify-content: space-between;
- border-bottom: 1px solid $alpha-grid-color;
- margin-bottom: $sp;
-
- .meta {
- margin-bottom: $sp*0.5;
- }
-
- > *:last-child {
- margin-bottom: $sp*0.5;
- }
-
- li {
- display: inline;
- white-space: nowrap;
- &:not(:last-child) {
- margin-right: 2vw;
- }
- }
-
- @media only screen and (max-width: $sections-width) {
- flex-direction: column;
- }
-}
-.layout-page.has-image {
- .pagenav {
- border-bottom: none;
- margin-bottom: 0;
- }
-}
-#hero-map {
- width: 100%;
- height: 50vw;
- max-height: 70vh;
- min-height: 30vh;
- border-bottom: 1px solid $grid-color;
-
- .custom-marker {
- background-color: var(--color);
- border-radius: 50%;
- width: 20px;
- height: 20px;
- cursor: pointer;
- }
-
- .custom-marker::after {
- position: absolute;
- content: '';
- background-image: var(--icon-image);
- background-position: center;
- background-size: 70%;
- background-repeat: no-repeat;
- filter: invert(1);
- width: 100%;
- height: 100%;
- border-radius: 50%;
- }
-
- .custom-marker::before {
- position: absolute;
- content: '';
- width: 0px;
- height: 0px;
- bottom: -100%;
- border: 10px solid transparent;
- border-top: 17px solid var(--color);
- }
-}
-
-figcaption {
- background-color: rgba(0,0,0,0.5);
- -webkit-backdrop-filter: blur(10px);
- backdrop-filter: blur(10px);
- position: absolute;
- right: 0;
- bottom: 0;
- max-width: min($text-width*0.8, 100%);
- padding: calc($sp/6) calc($sp/4);
- font-style: italic;
- line-height: 1.3;
- font-size: 0.9em;
- color: white;
-
- a, a:visited {
- color: #00e723;
- }
- a:hover, a:focus, a:active {
- color: #00ff27;
- }
-
- &.left {
- right: initial;
- left: 0;
- }
-}
-
-.cover {
- color: white;
- width: 100%;
- position: relative;
- background-position: center;
- background-size: cover;
- overflow-x: hidden;
-
- .pagenav {
- border-bottom-color: rgba(255, 255, 255, 0.25);
- }
-
- &.video {
- background: black;
- line-height: 0;
- }
-
- .cover-image-container {
- position: relative;
- }
-
- .cover-image {
- border: 1px solid $grid-color;
- }
-
- .cover-image, .cover-video {
- width: 100%;
- max-height: min(70vh, 50vw);
- height: $cover-image-height;
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
- position: relative;
- }
-
- figcaption {
- right: 1px;
- bottom: 1px;
- max-width: min($text-width*0.8, calc(100%) - 2px);
- }
-}
-.layout-project .cover, .layout-person .cover {
- background: linear-gradient(-135deg, #002042, #022D48);
-}
-
-iframe.embedded-page-viewer {
- width: 100%;
- height: calc(80vh - $topbar-height);
- border: 1px solid $grid-color;
- border-radius: 4px;
- overflow: hidden;
-}
-
-/* Project page
---------------------------------------------
-*/
-$hero-overlap: 150px;
-
-.layout-project {
-
- .cover {
- .logo-area {
- display: flex;
-
- > * {
- width: 100%;
- }
-
- .logo-wrap {
- flex: 0 0 auto;
- width: $avatar-width;
- max-height: $avatar-width*1.25;
- margin-right: $sp*1.5;
- text-align: center;
-
- img {
- max-width: 100%;
- max-height: 100%;
- }
- }
- @media only screen and (max-width: $sections-width) {
- flex-direction: column;
-
- .logo-wrap {
- margin-right: 0;
- margin-bottom: $sp;
- }
-
- img.wordmark {
- margin-top: 0;
- }
- }
- }
- a {
- display: inline-block;
- color: inherit;
- }
- > .container {
- margin-top: $sp;
- margin-bottom: $sp;
- }
- &.with-hero-image {
- padding-bottom: $hero-overlap;
- }
-
- .blurb a {
- text-decoration: underline;
- }
- }
-
- img.wordmark {
- max-width: 100%;
- max-height: 86px;
- }
-
- .blurb, .tagline {
- max-width: $text-width;
- }
-
- .cover .container .logo-area .right > *:not(:last-child) {
- margin-bottom: $sp*0.5;
- }
- .tagline {
- font-style: italic;
- font-weight: bold;
- font-size: 20px;
- }
- img.hero-image {
- width: 100%;
- border-radius: 5px;
- border: 1px solid $alpha-grid-color;
- margin-top: -$hero-overlap;
- }
-
-}
-
-.buttons {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-top: $sp;
-
- margin-bottom: -$sp;
-
- a {
- margin-bottom: $sp;
- }
- .button {
- flex: 0 0 auto;
- }
- .text-buttons > .button:not(:last-child) {
- margin-right: $sp*0.75;
- }
-
- @media only screen and (max-width: $sections-width) {
- flex-direction: column;
- align-items: baseline;
- }
-}
-.banner-footer {
- width: 100%;
- padding-top: $sp;
- position: relative;
- color: #fff;
-}
-table.schedule {
- table-layout: auto;
- th, td {
- padding: 10px 14px;
- border-right: 1px solid $grid-color;
- &:first-child {
- border-left: 1px solid $grid-color;
- }
- }
- td {
- &:first-child {
- width: 100px;
- }
- .title {
- font-weight: 600;
- }
- }
-
- tr {
- transition: 200ms ease-in-out;
- }
-
- tr.interstitial {
- background: hsl(0, 0%, 97%);
- .title {
- font-weight: normal;
- font-style: italic;
- }
- }
-
- tr.ongoing {
- border-top: 2px solid $status-color;
- background: #E5F7FC;
- td:first-child {
- padding-top: 18px;
- font-weight: 600;
- position: relative;
-
- &:before {
- content: "Happening Now";
- display: block;
- position: absolute;
- top: -14px;
- border-radius: 13px;
- background-color: $status-color;
- color: white;
- font-size: 14px;
- font-weight: bold;
- width: 124px;
- height: 26px;
- text-align: center;
- left: -13px;
- }
- }
- .title {
- font-weight: bold;
- }
- }
-}
-
-.icon-buttons {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- > li {
- &:not(:last-child) {
- margin-right: $sp*0.25;
- }
- }
- .iconsvg {
- vertical-align: middle;
- height: 30px;
- width: 30px;
- }
-}
-
-.section {
- width: 100%;
- .section-header {
- border-bottom: 1px solid $alpha-grid-color;
- margin-bottom: $sp;
- display: flex;
- align-items: baseline;
- justify-content: space-between;
-
- h2, h3 {
- white-space: nowrap;
- }
- }
- a.section-button {
- font-weight: 600;
- }
- margin-bottom: $sp;
-
- & > *:not(.prose) {
- h1, h2, h3, h4, h5, h6 {
- font-family: $serif-font !important;
- }
- }
- &:empty {
- display: none;
- }
-}
-
-/* Person page
---------------------------------------------
-*/
-.layout-person {
- $avatar-border-width: 5px;
-
- h1 {
- margin: 0;
- }
-
- .cover {
- min-height: 200px;
- }
-
- &.has-cover {
- .cover {
- background: none;
- }
- }
-
- .hero-avatar {
- width: 100%;
- padding-bottom: calc(100% - $avatar-border-width*2);
- position: relative;
- margin-top: -84px;
- border: $avatar-border-width solid $background-color;
- }
-
- .sections {
- display: flex;
- flex-direction: column;
- }
- .section {
- width: auto;
- display: flex;
- justify-content: right;
- margin: 0 auto;
-
- .section-body {
- padding: $sp*0.75;
- padding-left: 0;
- border-bottom: 1px solid $grid-color;
-
- &.prose {
- padding-bottom: 0;
- }
- }
-
- > h3 {
- padding-top: $sp*0.75;
- }
-
- > *:first-child {
- width: 210px;
- text-align: right;
- padding-right: $sp*0.75;
- }
- > *:last-child {
- width: $text-width;
- max-width: 100%;
- flex: 0 0 auto;
- border-right: 1px solid $grid-color;
- }
- &:last-child > *:last-child {
- border-bottom: 0;
- }
-
- .name-header {
- padding-top: 0;
- }
- }
- .connect-links a:not(:last-child) {
- margin-right: $sp;
- }
-
- @media only screen and (max-width:$sections-width) {
- .hero-avatar {
- margin-left: auto;
- margin-right: auto;
- width: 210px;
- height: 210px;
- padding: 0;
- }
- .cover figcaption {
- top: 1px;
- bottom: initial;
- }
- .name-header {
- text-align: center;
- }
- .sections {
- padding-left: $sp*0.75;
- }
- .section {
- flex-direction: column;
- width: 100%;
-
-
- > *:first-child {
- width: 100%;
- margin: 0 auto;
- max-width: $text-width;
- text-align: center;
- }
- > h3 {
- border-right: 1px solid $grid-color;
- }
- > h3:empty {
- display: none;
- }
- > *:last-child {
- margin: 0 auto;
- }
- }
- }
-}
-
-.item-list {
- position: relative;
-
- .item-listing {
- display: flex;
- justify-content: left;
- max-width: 100%;
- &:not(:last-child) {
- margin-bottom: $sp;
- }
-
- .listing-front {
- max-width: 100%;
- width: 360px;
- position: relative;
- flex: 0 0 auto;
-
- &:empty {
- height: 0;
- }
-
- .thumbnail-image {
- position: relative;
- width: 100%;
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
- display: block;
- border: 1px solid $alpha-grid-color;
-
- transition: transform 100ms ease-in-out;
-
- &:hover {
- transform: scale(1.04);
- z-index: 9999;
-
- .iconsvg {
- opacity: 0.9;
- }
- }
-
- .iconsvg {
- color: white;
- opacity: 0.75;
- width: 20px;
- height: 20px;
- position: absolute;
- right: 10px;
- bottom: 10px;
- }
- }
- .rect-image {
- border-radius: 2px;
- height: $list-item-image-height;
- }
- }
-
- .listing-body {
- padding-left: $sp;
- max-width: $text-width;
-
- &:empty {
- display: none;
- }
- &:first-child {
- padding-left: 0;
- }
-
- & > * {
- margin-bottom: $sp*0.25;
- }
- .button {
- margin-top: $sp*0.25;
- }
- .subtitle {
- line-height: 1.2;
- font-style: italic;
- }
- }
-
- &.contained-image {
- .listing-front {
- width: $avatar-width;
- }
- }
- &.contained-image .thumbnail-image,
- .thumbnail-image.contained-image {
- height: $list-item-image-height;
- background-size: contain;
- border: 0;
- }
-
- @media only screen and (max-width: $sections-width) {
- flex-wrap: wrap;
- .listing-front {
- width: 100%;
- }
- .listing-body {
- padding-left: 0;
- padding-top: $sp*0.5;
- }
- }
- }
-
- &.gallery {
- display: flex;
- flex-wrap: wrap;
- .item-listing {
- flex-direction: column;
- align-items: center;
- text-align: center;
- width: $avatar-width;
- flex: 0 0 auto;
-
- .listing-front {
- width: 100%;
- }
- .thumbnail-image {
- width: 80%;
- padding-bottom: 80%;
- margin: 0 auto;
- }
-
- .listing-body {
- padding: 0;
- margin-top: $sp*0.5;
- }
- }
-
- @media only screen and (max-width: calc($avatar-width*2 + $container-padding*2)) {
- &:not(.scroll) {
- justify-content: center;
- }
- }
- &:not(.pages-list):not(.people-list):not(.swag-list) {
-
- .item-listing {
- width: calc($content-width * 0.333);
-
- align-items: baseline;
- .listing-front .thumbnail-image {
- width: 92%;
- padding: 0;
- }
-
- .listing-body {
- width: 92%;
- margin-left: auto;
- margin-right: auto;
- }
-
- h3 {
- text-align: left;
- }
- }
-
- &.no-titles {
-
- .item-listing {
- margin: 0;
- .listing-front .thumbnail-image {
- height: 196px;
- width: 100%;
- border-radius: 0;
- border-width: 0.5px;
- }
-
- }
- }
-
- &.scroll {
- .item-listing {
- width: calc($content-width * 0.27);
- .listing-front .thumbnail-image {
- height: 148px;
- }
- }
- .thumbnail-image, .listing-body {
- margin-left: 0;
- }
- }
- }
- }
-
- &.people-list {
-
- .listing-front {
- width: $avatar-width;
- height: auto;
-
- .thumbnail-image {
- width: 80%;
- padding-bottom: 80%;
- margin: 0 auto;
- }
- }
- .listing-body {
- padding-left: $sp*0.5;
- }
- }
-
- &.scroll {
- flex-wrap: nowrap;
- overflow-x: auto;
- }
-
- &.swag-list {
- h3 {
- font-family: $sans-serif-font !important;
- font-size: 1em;
- }
- }
-}
-
-.simple-item-listing {
- display: flex;
- justify-content: space-between;
- line-height: 1.25;
- .date {
- white-space: nowrap;
- }
- &:not(:last-child) {
- margin-bottom: $sp*0.75;
- }
-}
-
-.title {
- .iconsvg {
- width: 0.6em;
- height: 0.6em;
- }
-}
-
-.content {
- padding-top: $sp;
- padding-bottom: $sp*2;
- width: 100%;
-}
-
-article {
- position: relative;
- margin: auto;
- display: flex;
- flex-direction: column;
- align-items: center;
-
- .post-header {
- padding-top: $sp;
- width: 100%;
- margin: 0 auto;
- position: relative;
- }
- .post-body {
- margin-bottom: $sp*2;
- }
-}
-
-.prose {
- display: flex;
- flex-direction: column;
- align-items: baseline;
- position: relative;
- z-index: 0;
-
- h2, h3, h4, h5, h6 {
- font-family: $sans-serif-font;
- }
-
- li {
- list-style: disc;
- margin-left: 20px;
- }
- ol {
- li {
- list-style: decimal;
- }
- }
-
- >, blockquote {
-
- .neatline {
- position: absolute;
- height: calc(100% + $sp);
- width: calc(100% + $container-padding);
- max-width: calc($text-width + $sp*2);
- left: 0;
- right: 0;
- top: -$sp;
- border-right: 1px solid $grid-color;
- z-index: -1;
-
- @media only screen and (max-width: calc($text-width + $container-padding*2)) {
- display: none;
- }
- }
-
- iframe, table, form, a, em, b, strong, i, p, ol, ul,
- code, blockquote, q, h1, h2, h3, h4, h5, h6, hr, pre, center {
- width: 100%;
- max-width: $text-width;
- margin-bottom: $sp;
- }
- img, figure, .img-container, div {
- margin-bottom: $sp;
- }
- hr {
- padding: 0;
- width: 100%;
- max-width: calc($text-width + $sp*2);
- position: relative;
- }
- img, figure, .img-container, iframe, table {
- max-width: $img-width;
- border: 1px solid $grid-color;
- background-color: $background-color;
- padding: 0;
-
- &.wide {
- max-width: 100%;
- }
-
- @media only screen and (max-width: calc($img-width + $container-padding*2)) {
- max-width: 100%;
- }
- }
- figure, .img-container {
- line-height: 0;
- position: relative;
-
- img {
- width: 100%;
- }
- }
- blockquote, q {
- position: relative;
- left: 0.75em;
- padding-left: $sp;
- border-left: 6px solid $grid-color;
- width: calc(100% - 1em);
- max-width: calc($text-width - 1em);
- }
- }
-}
-
-/* About
-------------------------------------------------------- */
-.board-members img {
- max-width: 50%;
- margin: 0px auto 10px auto;
- display: block;
-}
-
-.board-members p {
- margin-bottom: 40px;
-}
-
-
-/* Blog Post
-------------------------------------------------------- */
-
-.avatar {
- background-image: url($baseurl + "/assets/avatar.jpg");
- background-color: white;
- border-radius: 50%;
- background-size: cover;
- background-position: center;
- flex: 0 0 auto;
-}
-
-.inline-avatar {
- display: inline-block;
- vertical-align: text-top;
- width: 24px;
- height: 24px;
- margin-right: 4px;
-}
-
-/* 404
-------------------------------------------------------- */
-.notfound {
- padding: 100px 100px;
- text-align: center;
- color: #999;
- text-shadow: 1px 1px 2px #eee;
- font-size: 25px;
-}
-.notfound h1 {
- font-size: 50px;
-}
-
-/* Footer
-------------------------------------------------------- */
-.footer {
- min-height: $footer-min-height;
- font-size: 17px;
- border-top: 1px solid rgb(60, 60, 60);
- position: relative;
- margin-top: 0px;
- display: flex;
- flex-flow: row nowrap;
- padding: $sp 0;
-
- .top {
- display: flex;
- justify-content: space-between;
-
- @media only screen and (max-width: $sections-width) {
- flex-direction: column;
-
- .site-wordmark {
- margin-bottom: $sp;
- }
- }
- }
-
- .sitemap {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- ul {
- width: $avatar-width;
- margin-bottom: $sp;
- li {
- white-space: nowrap;
-
- &:first-child {
- font-weight: 600;
- }
- &:not(:last-child) {
- margin-right: $sp*0.5;
- }
- }
- }
- a {
- color: inherit;
- }
- }
-
- .smallprint {
- display: flex;
- justify-content: space-between;
- }
-}
-
-.status-bubble {
- color: white;
- background: $status-color;
- border-radius: 20px;
- position: absolute;
- top: -10px;
- font-weight: bold;
- font-size: 0.75em;
- padding: 0 $sp*0.5;
-}
-
-.app-sign {
- background-position: center;
- background-size: cover;
- border-radius: 16px;
- border: 1px solid $grid-color;
- height: 140px;
-
- .status-bubble {
- top: -10px;
- right: -10px;
- }
-}
-.status-symbol {
- color: $status-color;
-}
-
-.hoverscale {
- transition: transform 100ms ease-in-out;
-
- &:hover {
- transform: scale(1.04);
- z-index: 9999;
- }
-}
-
-.mono-logos {
- img {
- filter: brightness(0) invert(1);
- }
-}
-
-ul.org-members {
-
- padding-left: $sp*1.5;
-
- display: flex;
- flex-wrap: wrap;
-
- li {
- max-width: 100%;
- list-style: none;
- margin-left: 0;
- margin-bottom: $sp;
- &:not(:last-child) {
- margin-right: $sp*2;
- }
-
- img {
- width: auto;
- height: 100%;
- max-width: 100%;
- object-fit: contain;
- }
- }
-}
-
-ul.org-members.level-5 li {
- height: 70px;
-}
-
-ul.org-members.level-4 li {
- height: 80px;
-}
-
-ul.org-members.level-3 li {
- height: 90px;
-}
-
-ul.org-members.level-2 li {
- height: 100px;
-}
-
-ul.org-members.level-1 li {
- height: 108px;
-}
-
-.directory {
- display: flex;
- flex-wrap: wrap;
- .list-wrap {
- flex-basis: 25%;
- min-width: 200px;
- padding-bottom: $sp;
- padding-right: $sp*0.5;
- white-space: nowrap;
- }
-}
-
-#notice-overlay {
- position: fixed;
- bottom: $sp*0.5;
- right: $sp*0.5;
- background: white;
- border: 1px solid $grid-color;
- border-radius: 4px;
- padding: $sp*0.75 $sp*0.5;
- box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.12);
-
- display: flex;
- flex-direction: row;
-
- .logo {
- width: 60px;
- margin-right: $sp*0.5;
- }
- .status-bubble {
- left: -10px;
- }
-}
-
-.cond-only {
- display: none;
-}
-.condensed {
- .no-cond {
- display: none;
- }
-}
-.condensed {
- .cond-only {
- display: initial;
- }
-}
-.condensed {
- .simple-item-listing > *:first-child {
- display: flex;
- flex-direction: column;
- }
-}
-@media only screen and (max-width: $sections-width) {
- .no-cond {
- display: none !important;
- }
- .cond-only {
- display: initial;
- }
-
- .simple-item-listing > *:first-child {
- display: flex;
- flex-direction: column;
- }
-}
\ No newline at end of file
diff --git a/_sass/dogwood/custom-variables.scss b/_sass/dogwood/custom-variables.scss
index 2a2d0fa..59ea803 100644
--- a/_sass/dogwood/custom-variables.scss
+++ b/_sass/dogwood/custom-variables.scss
@@ -1 +1,5 @@
-// Placeholder to allow overriding predefined variables smoothly.
+$background-color: white;
+$primary-color: #22b663;
+$primary-color-alt: #22b663;
+$status-color: #930041;
+
diff --git a/_sass/dogwood/initialize.scss b/_sass/dogwood/initialize.scss
deleted file mode 100644
index ff620bd..0000000
--- a/_sass/dogwood/initialize.scss
+++ /dev/null
@@ -1,44 +0,0 @@
-@charset "UTF-8";
-
-$sans-serif-font: Helvetica, Arial, sans-serif;
-$serif-font: Georgia, serif;
-
-$background-color: white;
-$primary-color: #22b663;
-$primary-color-alt: #22b663;
-$status-color: #930041;
-
-$grid-color: #dedede;
-/* the below should look the same as the above when on a white bg */
-/* $alpha-grid-color: rgba(0, 0, 0, 0.13); */
-$alpha-grid-color: rgba(128, 128, 128, 0.26);
-$text-color: #333;
-$dark-background-color: #333;
-$dark-grid-color: rgba(255, 255, 255, 0.13);
-
-$body-text-size: 18px;
-$sp: 24px;
-$container-width: 1100px;
-$container-padding: $sp*0.75;
-$content-width: calc($container-width - $container-padding * 2);
-$cover-image-height: $container-width * 0.5;
-$text-width: 700px;
-$img-width: 880px;
-
-$footer-min-height: 490px;
-
-$topbar-height: 54px;
-
-$avatar-width: calc($content-width * 0.2);
-
-$sections-width: 720px;
-
-$list-item-image-height: 180px;
-
-// Import pre-styling-overrides hook and style-partials.
-@import
- "dogwood/custom-variables", // Hook to override predefined variables.
- "dogwood/base", // Defines element resets.
- "dogwood/layout", // Defines structure and style based on CSS selectors.
- "dogwood/custom-styles" // Hook to override existing styles.
-;
diff --git a/_tools/embedded-page-cacher/index.js b/_tools/embedded-page-cacher/index.js
deleted file mode 100644
index e6b9cdc..0000000
--- a/_tools/embedded-page-cacher/index.js
+++ /dev/null
@@ -1,139 +0,0 @@
-// embedded-page-cacher for dogwood
-//
-// This script saves local versions of remote pages linked
-// in the `embedded_remote` property of `_posts`. Pages
-// and their images are saved to `/embeds/cached/` with the
-// full local URL saved to the `embedded` property. You can
-// then use the `embedded-page` layout to display these pages
-// in an iframe.
-//
-// This script is used on openstreetmap.us to cache our newsletters.
-// Cacheing ensures the content will always be available, but also
-// fixes cross-origin issues with iframes. For instance, we want
-// clicked links to open in the browser window and not within the iframe.
-
-import fs from 'fs';
-import followRedirects from 'follow-redirects';
-const https = followRedirects.https;
-import graymatter from 'gray-matter';
-import filenamifyUrl from 'filenamify-url';
-
-import process from 'process';
-import minimist from 'minimist';
-const argv = minimist(process.argv.slice(2));
-let sourcePath = process.env.npm_config_srcdir || argv.srcdir || '.';
-if (sourcePath.endsWith('/')) sourcePath.slice(0, -1);
-
-const inDir = sourcePath + '/_posts';
-const outRelativeDir = '/embeds/cached'
-const outDir = sourcePath + outRelativeDir;
-
-if (!fs.existsSync(outDir)) fs.mkdirSync(outDir);
-
-cacheRemoteLinks(inDir);
-
-function cacheRemoteLinks(path) {
-
- const dir = fs.opendirSync(path);
- let dirent;
- while ((dirent = dir.readSync()) !== null) {
- const subpath = path + '/' + dirent.name;
- if (dirent.isFile()) {
-
- const filedata = fs.readFileSync(subpath);
- const frontmatter = graymatter(filedata);
-
- // ignore files not in Jekyll format
- if (Object.keys(frontmatter.data).length > 0) {
- let remoteUrl = frontmatter.data.embedded_remote;
- if (remoteUrl) {
- let slug = filenamifyUrl(remoteUrl);
- let outPath = outDir + '/' + slug + '/';
- if (!fs.existsSync(outPath)) {
- fs.mkdirSync(outPath);
- cacheRemoteWebpage(remoteUrl, outPath);
-
- frontmatter.data.embedded = outRelativeDir + '/' + slug;
-
- let newFileContent = graymatter.stringify(frontmatter, frontmatter.data);
- fs.writeFileSync(subpath, newFileContent);
- console.log(`updated ${subpath}`);
- }
- }
- }
- } else if (dirent.isDirectory()) {
- cacheRemoteLinks(subpath);
- }
- }
- dir.closeSync();
-}
-
-
-function cacheRemoteWebpage(url, toPath) {
- console.log(url);
-
- var content = "";
-
- var req = https.request(url, function(res) {
- res.setEncoding("utf8");
- res.on("data", function (chunk) {
- content += chunk;
- });
-
- res.on("end", function () {
- content = content.trim()
- // we want all links to open in new tabs instead of in the iframe
- .replace('', '');
-
- content = cacheRemoteImages(content, toPath);
-
- fs.writeFileSync(toPath + "index.html", content);
- console.log(`cached ${url} to ${toPath}`);
- });
- });
-
- req.on('error', (e) => {
- console.error(`problem with request: ${e.message}`);
- });
-
- req.end();
-}
-
-function cacheRemoteImage(url, toPath) {
-
- var content = "";
-
- var req = https.request(url, function(res) {
- res.setEncoding('binary');
- res.on("data", function (chunk) {
- content += chunk;
- });
-
- res.on("end", function () {
- fs.writeFileSync(toPath, content, "binary");
- console.log(`cached ${url} to ${toPath}`);
- });
- });
-
- req.on('error', (e) => {
- console.error(`problem with request: ${e.message}`);
- });
-
- req.end();
-}
-
-function cacheRemoteImages(html, toPath) {
- if (!fs.existsSync(toPath + "img/")){
- fs.mkdirSync(toPath + "img/");
- }
-
- let imgRegex = /src="(\S+?\.(?:png|jpg|jpeg|gif|svg|tif|tiff|pdf))\S*?"/gi;
- const matches = html.matchAll(imgRegex);
- for (const match of matches) {
- let imgUrl = match[1];
- let slug = filenamifyUrl(imgUrl);
- html = html.replaceAll(imgUrl, "img/" + slug);
- cacheRemoteImage(imgUrl, toPath + "img/" + slug);
- }
- return html;
-}
diff --git a/_tools/frontmatter-validator/index.js b/_tools/frontmatter-validator/index.js
deleted file mode 100644
index b687df2..0000000
--- a/_tools/frontmatter-validator/index.js
+++ /dev/null
@@ -1,97 +0,0 @@
-// frontmatter-validator for dogwood
-//
-// This script checks that the frontmatter in all your
-// Jekyll documents matches a known format. This is important
-// since the theme relies on many custom variables.
-//
-// By default, the script will throw an error if you have
-// additional properties to those expected. This catches
-// typos like `authors` instead of `author`. Use the
-// `--strict=false` option to turn off this behavior.
-
-import fs from 'fs';
-import graymatter from 'gray-matter';
-import path from 'path';
-import {fileURLToPath} from 'url';
-
-import process from 'process';
-import minimist from 'minimist';
-const argv = minimist(process.argv.slice(2));
-let sourcePath = process.env.npm_config_srcdir || argv.srcdir || '.';
-if (sourcePath.endsWith('/')) sourcePath.slice(0, -1);
-
-import ZSchema from 'z-schema';
-
-let zSchemaOptions = {};
-
-let isStrict = true;
-if (("npm_config_strict" in process.env && !process.env.npm_config_strict) ||
- process.argv.includes("--strict=false")) {
- isStrict = false;
-}
-
-if (isStrict) {
- let strictOptions = {
- assumeAdditional: true,
- forceItems: true,
- forceMinItems: true,
- forceMinLength: true,
- forceProperties: true,
- noEmptyArrays: true,
- noEmptyStrings: true,
- noExtraKeywords: true,
- noTypeless: true,
- };
- Object.assign(zSchemaOptions, strictOptions);
-}
-
-const jsonValidator = new ZSchema(zSchemaOptions);
-
-let hasInvalid = false;
-
-function validateJson(json, schema) {
- const valid = jsonValidator.validate(json, schema);
- const errors = jsonValidator.getLastErrors();
- if (!valid) {
- errors.forEach(function(error) {
- console.log(error);
- });
- hasInvalid = true;
- }
-}
-
-function validateFrontmatter(path, schemaPath) {
- const schema = JSON.parse(fs.readFileSync(schemaPath));
- const dir = fs.opendirSync(path);
- let dirent;
- while ((dirent = dir.readSync()) !== null) {
- const subpath = path + '/' + dirent.name;
- if (dirent.isFile()) {
- const filedata = fs.readFileSync(subpath);
- const info = graymatter(filedata);
-
- // ignore files not in Jekyll format
- if (Object.keys(info.data).length > 0) {
- // parse to string and back again to make sure dates are in string format
- let data = JSON.parse(JSON.stringify(info.data));
- validateJson(data, schema);
- }
- } else if (dirent.isDirectory()) {
- validateFrontmatter(subpath, schemaPath);
- }
- }
- dir.closeSync();
-}
-
-const directory = path.dirname(fileURLToPath(import.meta.url));
-var schemasDir = path.join(directory, '/schemas');
-
-validateFrontmatter(sourcePath + '/_posts', schemasDir + '/post.json');
-validateFrontmatter(sourcePath + '/_people', schemasDir + '/person.json');
-validateFrontmatter(sourcePath + '/_pages', schemasDir + '/page.json');
-validateFrontmatter(sourcePath + '/_redirects', schemasDir + '/redirect.json');
-
-if (hasInvalid) {
- // nonzero exit for GitHub Actions
- process.exit(1);
-}
\ No newline at end of file
diff --git a/_tools/frontmatter-validator/schemas/page.json b/_tools/frontmatter-validator/schemas/page.json
deleted file mode 100644
index 84cef98..0000000
--- a/_tools/frontmatter-validator/schemas/page.json
+++ /dev/null
@@ -1,281 +0,0 @@
-{
- "title": "Page",
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "temp_title": {
- "type": "string"
- },
- "short_title": {
- "type": "string"
- },
- "tagline": {
- "type": "string"
- },
- "temp_tagline": {
- "type": "string"
- },
- "blurb": {
- "type": "string"
- },
- "temp_blurb": {
- "type": "string"
- },
- "layout": {
- "type": "string"
- },
- "event": {
- "type": "string"
- },
- "event_series": {
- "type": "string"
- },
- "caption": {
- "type": "string"
- },
- "status": {
- "type": "string"
- },
- "location": {
- "type": "string"
- },
- "image": {
- "type": "string"
- },
- "sign": {
- "type": "string"
- },
- "logo": {
- "type": "string"
- },
- "wordmark": {
- "type": "string"
- },
- "icon": {
- "type": "string"
- },
- "website": {
- "type": "string"
- },
- "twitter": {
- "type": "string"
- },
- "youtube_page": {
- "type": "string",
- "description": "Path to a page on youtube.com. Different from `youtube` since that parameter is a video ID which is used differently."
- },
- "facebook": {
- "type": "string"
- },
- "slack_channel": {
- "type": "string"
- },
- "instagram": {
- "type": "string"
- },
- "email_list": {
- "type": "string"
- },
- "meetup": {
- "type": "string"
- },
- "reddit": {
- "type": "string"
- },
- "mastodon": {
- "type": "string"
- },
- "donate": {
- "type": "string"
- },
- "links": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "label": {
- "type": "string"
- },
- "link": {
- "type": "string"
- }
- }
- }
- },
- "swag_items": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "url": {
- "type": "string"
- },
- "image": {
- "type": "string"
- }
- }
- }
- },
- "swag_sections": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "items": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "url": {
- "type": "string"
- },
- "image": {
- "type": "string"
- }
- }
- }
- }
- }
- }
- },
- "dropdown_links": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "label": {
- "type": "string"
- },
- "link": {
- "type": "string"
- }
- }
- }
- },
- "app_links": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "label": {
- "type": "string"
- },
- "link": {
- "type": "string"
- }
- }
- }
- },
- "footer_links": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "label": {
- "type": "string"
- },
- "link": {
- "type": "string"
- }
- }
- }
- },
- "buttons": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "label": {
- "type": "string"
- },
- "link": {
- "type": "string"
- }
- }
- }
- },
- "sessions": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "blurb": {
- "type": "string"
- },
- "date": {
- "oneOf": [
- {
- "type": "string",
- "format": "date-time"
- },
- {
- "type": "string",
- "pattern": "\\d{4}-[01]\\d-[0-3]\\d [0-2]\\d:[0-5]\\d(:[0-5]\\d)? ([+-][0-2]\\d[0-5]\\d)"
- }
- ]
- }
- }
- }
- },
- "section_tags": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "team_name": {
- "type": "string"
- },
- "max_posts": {
- "type": "integer"
- },
- "updated": {
- "type": "string",
- "format": "date-time"
- },
- "timezone": {
- "type": "string"
- },
- "filter_start": {
- "type": "string",
- "format": "date-time"
- },
- "filter_end": {
- "type": "string",
- "format": "date-time"
- },
- "start": {
- "type": "string",
- "format": "date-time"
- },
- "end": {
- "type": "string",
- "format": "date-time"
- },
- "map": {
- "type": "object",
- "properties": {
- "points": {
- "type": "string"
- }
- }
- }
- },
- "required": [
- "title"
- ]
- }
\ No newline at end of file
diff --git a/_tools/frontmatter-validator/schemas/person.json b/_tools/frontmatter-validator/schemas/person.json
deleted file mode 100644
index f2d0cda..0000000
--- a/_tools/frontmatter-validator/schemas/person.json
+++ /dev/null
@@ -1,77 +0,0 @@
-{
- "title": "Person",
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "updated": {
- "type": "string",
- "format": "date-time"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "at": {
- "type": "string"
- },
- "from": {
- "type": "string",
- "format": "date-time"
- },
- "to": {
- "type": "string",
- "format": "date-time"
- }
- },
- "required": [
- "at"
- ]
- }
- },
- "image": {
- "type": "string"
- },
- "image_remote": {
- "type": "string"
- },
- "cover": {
- "type": "string"
- },
- "caption": {
- "type": "string"
- },
- "linkedin": {
- "type": "string"
- },
- "twitter": {
- "type": "string"
- },
- "github": {
- "type": "string"
- },
- "osm": {
- "type": "string"
- },
- "website": {
- "type": "string"
- },
- "wikipedia": {
- "type": "string"
- },
- "mastodon": {
- "type": "string"
- },
- "medium": {
- "type": "string"
- }
- },
- "required": [
- "title"
- ]
- }
\ No newline at end of file
diff --git a/_tools/frontmatter-validator/schemas/post.json b/_tools/frontmatter-validator/schemas/post.json
deleted file mode 100644
index 7dbdbfe..0000000
--- a/_tools/frontmatter-validator/schemas/post.json
+++ /dev/null
@@ -1,113 +0,0 @@
-{
- "title": "session",
- "type": "object",
- "properties": {
- "title": {
- "type": "string"
- },
- "embedded": {
- "type": "string"
- },
- "embedded_remote": {
- "type": "string"
- },
- "permalink": {
- "type": "string"
- },
- "event": {
- "type": "string"
- },
- "blurb": {
- "type": "string"
- },
- "date": {
- "oneOf": [
- {
- "type": "string",
- "format": "date-time"
- },
- {
- "type": "string",
- "pattern": "\\d{4}-[01]\\d-[0-3]\\d [0-2]\\d:[0-5]\\d(:[0-5]\\d)? ([+-][0-2]\\d[0-5]\\d)"
- }
- ]
- },
- "image": {
- "type": "string"
- },
- "image_remote": {
- "type": "string"
- },
- "caption": {
- "type": "string"
- },
- "youtube": {
- "type": ["string", "null"]
- },
- "video_src": {
- "type": "string"
- },
- "podbean": {
- "type": "string"
- },
- "register": {
- "type": "string"
- },
- "slides": {
- "type": "string"
- },
- "author": {
- "oneOf": [
- {
- "type": "string"
- },
- {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- ]
- },
- "speaker": {
- "oneOf": [
- {
- "type": "string"
- },
- {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- ]
- },
- "tags": {
- "type": "array",
- "items": {
- "type": "string"
- }
- },
- "block": {
- "type": "string"
- },
- "time": {
- "type": "string"
- },
- "day": {
- "type": "string"
- },
- "room": {
- "type": "string"
- },
- "length": {
- "type": "string"
- },
- "type": {
- "type": "string"
- }
- },
- "required": [
- "title"
- ]
- }
\ No newline at end of file
diff --git a/_tools/frontmatter-validator/schemas/redirect.json b/_tools/frontmatter-validator/schemas/redirect.json
deleted file mode 100644
index 56113a8..0000000
--- a/_tools/frontmatter-validator/schemas/redirect.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "title": "Redirect",
- "type": "object",
- "properties": {
- "permalink": {
- "type": "string"
- },
- "redirect": {
- "type": "string"
- },
- "title": {
- "type": "string"
- }
- },
- "required": [
- "redirect"
- ]
- }
\ No newline at end of file
diff --git a/_tools/image-cacher/index.js b/_tools/image-cacher/index.js
deleted file mode 100644
index ea0f598..0000000
--- a/_tools/image-cacher/index.js
+++ /dev/null
@@ -1,112 +0,0 @@
-// image-cacher for dogwood
-//
-// This script fetches remote images referenced in the `image`
-// property of `_posts` and `_people` and saves them locally.
-// Remote images are sometimes a convenience but they are liable
-// to turn into 404s or 403s in time.
-//
-// Cached images are saved to `/img/posts/cached/` and /img/people/cached/`,
-// the `image` property is changed to the local file, and the original `image`
-// value is moved to `image_remote` for future reference.
-//
-// Remember to re-run the thumbnail-generator tool after cacheing images.
-
-import fs from 'fs';
-import followRedirects from 'follow-redirects';
-const https = followRedirects.https;
-import graymatter from 'gray-matter';
-
-import process from 'process';
-import minimist from 'minimist';
-const argv = minimist(process.argv.slice(2));
-let sourcePath = process.env.npm_config_srcdir || argv.srcdir || '.';
-if (sourcePath.endsWith('/')) sourcePath.slice(0, -1);
-
-const imgDir = 'img';
-
-const imgKeys = ['image', 'cover'];
-
-processFiles('_people', 'people');
-processFiles('_posts', 'posts');
-
-async function processFiles(jekyllSubdir, imageSubdir) {
- let jekyllDirPath = sourcePath + "/" + jekyllSubdir;
- const dir = fs.opendirSync(jekyllDirPath);
- let dirent;
- while ((dirent = dir.readSync()) !== null) {
- const subpath = jekyllDirPath + '/' + dirent.name;
- if (dirent.isFile()) {
- const filedata = fs.readFileSync(subpath);
- const info = graymatter(filedata);
-
- // ignore files not in Jekyll format
- if (Object.keys(info.data).length > 0) {
- let newFrontmatter = await cacheRemoteImages(info.data, imageSubdir);
- if (newFrontmatter) {
- let newFileContent = graymatter.stringify(info, newFrontmatter);
- fs.writeFileSync(subpath, newFileContent);
- console.log(`updated ${subpath}`);
- }
- }
- } else if (dirent.isDirectory()) {
- await processFiles(jekyllSubdir + '/' + dirent.name, imageSubdir);
- }
- }
- dir.closeSync();
-}
-
-async function cacheRemoteImage(url, toPath) {
-
- return new Promise((resolve) => {
-
- var content = "";
-
- var req = https.request(url, function(res) {
- if (res.statusCode !== 200) {
- console.error(`status ${res.statusCode} for ${url}`);
- resolve(false);
- return;
- }
- res.setEncoding('binary');
- res.on("data", function (chunk) {
- content += chunk;
- });
-
- res.on("end", function () {
- fs.writeFileSync(toPath, content, "binary");
- console.log(`cached ${url}`);
- resolve(true);
- });
- });
-
- req.on('error', (e) => {
- console.error(`problem with request: ${e.message}`);
- resolve(false);
- });
-
- req.end();
- });
-}
-
-async function cacheRemoteImages(frontmatter, imageSubdir) {
-
-
- var didCacheAny = false;
- for (var i in imgKeys) {
- var key = imgKeys[i];
- let imgUrl = frontmatter[key];
- if (imgUrl && imgUrl.startsWith('http')) {
- let slug = encodeURIComponent(imgUrl);
- frontmatter[key + "_remote"] = frontmatter[key];
-
- var cachedDirPath = imgDir + '/' + imageSubdir + '/cached/';
- if (!fs.existsSync(sourcePath + "/" + cachedDirPath)) fs.mkdirSync(sourcePath + "/" + cachedDirPath);
-
- let relativeOutPath = '/' + cachedDirPath + slug;
- frontmatter[key] = relativeOutPath;
- var didCache = await cacheRemoteImage(imgUrl, sourcePath + relativeOutPath);
- didCacheAny = didCacheAny || didCache;
- }
- }
- if (didCache) return frontmatter;
-}
diff --git a/_tools/people-validator/index.js b/_tools/people-validator/index.js
deleted file mode 100644
index 7a11cdd..0000000
--- a/_tools/people-validator/index.js
+++ /dev/null
@@ -1,106 +0,0 @@
-// people-validator for dogwood
-//
-// This script checks to make sure there is a document in the `_people`
-// directory for every `author` and `speaker` referenced in your `_posts`.
-// This isn't strictly necessary but it enables linking people with the
-// various content they're associated with.
-//
-// Use the `--fix=true` option to automatically create missing files.
-// Use the `--strict=false` option to output warnings instead of errors.
-//
-// Note that the name is the only unique identifier for a person. This
-// means you can only reference one person for each unique name,
-// and that different version of the name (Jim vs. Jimmy) will be
-// treated as different people.
-
-import fs from 'fs';
-import graymatter from 'gray-matter';
-
-import process from 'process';
-import minimist from 'minimist';
-const argv = minimist(process.argv.slice(2));
-let shouldFix = process.env.npm_config_fix || argv.fix;
-let hasUnfixedIssue = false;
-
-let sourcePath = process.env.npm_config_srcdir || argv.srcdir || '.';
-if (sourcePath.endsWith('/')) sourcePath.slice(0, -1);
-
-let isStrict = true;
-if (("npm_config_strict" in process.env && !process.env.npm_config_strict) ||
- process.argv.includes("--strict=false")) {
- isStrict = false;
-}
-
-let expectedPeople = {};
-
-function recordPostData(data) {
- let peopleKeys = ["author", "speaker"];
- peopleKeys.forEach(function(key) {
- let value = data[key];
- if (typeof value === 'string') {
- expectedPeople[value] = true;
- } else if (Array.isArray(value)) {
- value.forEach(function(item) {
- if (typeof item === 'string') {
- expectedPeople[item] = true;
- }
- });
- }
- });
-}
-
-function processFiles(path) {
- const dir = fs.opendirSync(path);
- let dirent;
- while ((dirent = dir.readSync()) !== null) {
- const subpath = path + '/' + dirent.name;
- if (dirent.isFile()) {
- const filedata = fs.readFileSync(subpath);
- const info = graymatter(filedata);
-
- // ignore files not in Jekyll format
- if (Object.keys(info.data).length > 0) {
- recordPostData(info.data);
- }
- } else if (dirent.isDirectory()) {
- processFiles(subpath);
- }
- }
- dir.closeSync();
-}
-
-function validatePeopleBasedOnPosts() {
- let peopleList = Object.keys(expectedPeople).sort();
- peopleList.forEach(function(name) {
- let slug = name.replaceAll(" ", "-").replaceAll(".", "").toLowerCase().normalize("NFD").replace(/\p{Diacritic}/gu, "");
- let path = sourcePath + '/_people/' + slug + '.md';
- if (!fs.existsSync(path)) {
- // ignore groups
- if (!name.match(/(Team|Committee|Organization|Staff|Board|Community|OpenStreetMap)/gi)) {
- if (shouldFix) {
- let newFileString = `---\ntitle: "${name}"\n---`;
- fs.writeFileSync(path, newFileString);
- console.log(`Created file for ${name} at ${path}`);
- } else {
- console.error(`Missing file for ${name} at ${path}`);
- hasUnfixedIssue = true;
- }
- }
- } else {
- let personData = graymatter(fs.readFileSync(path)).data;
- // the document title needs to match the name listed in the post meta or else Jekyll can't link them
- if (personData.title !== name) {
- console.error(`Unexpected name "${personData.title}" for ${name} at ${path}`);
- hasUnfixedIssue = true;
- }
- }
- });
-}
-
-processFiles(sourcePath + '/_posts');
-validatePeopleBasedOnPosts();
-
-if (hasUnfixedIssue && isStrict) {
- // nonzero exit for GitHub Actions
- process.exit(1);
-}
\ No newline at end of file
diff --git a/_tools/thumbnail-generator/index.js b/_tools/thumbnail-generator/index.js
deleted file mode 100644
index c5b5c31..0000000
--- a/_tools/thumbnail-generator/index.js
+++ /dev/null
@@ -1,68 +0,0 @@
-// thumbnail-generator for dogwood
-//
-// This script creates thumbnail versions of images that are displayed
-// at small sizes on some pages in order to reduce load times.
-// It is hardcoded for special directories (it works recursively):
-// /img/people/ – avatar images for people
-// /img/posts/ – header images for posts
-// And it saves the output to:
-// /img-thumbnails/people/
-// /img-thumbnails/posts/
-// In your Jekyll documents you should specify images like
-// "image: /img/posts/john.jpg" And the theme will automatically
-// output "/img-thumbnails/posts/john.jpg" in places where smaller
-// images are appropriate.
-//
-// Note that if you specify images in the special directories
-// but do not run this script before building your site then
-// your images will 404.
-
-import fs from 'fs';
-import sharp from 'sharp';
-
-import process from 'process';
-import minimist from 'minimist';
-const argv = minimist(process.argv.slice(2));
-let sourcePath = process.env.npm_config_srcdir || argv.srcdir || '.';
-if (sourcePath.endsWith('/')) sourcePath.slice(0, -1);
-
-var imgDir = sourcePath + '/img/';
-var imgThumbDir = sourcePath + '/img-thumbnails/';
-
-if (!fs.existsSync(imgThumbDir)) fs.mkdirSync(imgThumbDir);
-
-processFiles('posts', 720, null);
-processFiles('people', 48, 48);
-
-function processFiles(subdir, width, height) {
- let inDir = imgDir + subdir;
- let outDir = imgThumbDir + subdir;
-
- if (!fs.existsSync(outDir)) fs.mkdirSync(outDir);
-
- const dir = fs.opendirSync(inDir);
- let dirent;
- while ((dirent = dir.readSync()) !== null) {
-
- //ignore hidden files
- if (dirent.name[0] === '.') continue;
-
- if (dirent.isFile()) {
- const subpath = inDir + '/' + dirent.name;
- let outPath = outDir + '/' + dirent.name + '.webp';
- const buffer = fs.readFileSync(subpath);
-
- sharp(buffer, { animated: true, limitInputPixels: false })
- .resize(width, height, { withoutEnlargement: true })
- .toFile(outPath)
- .catch(err => {
- console.log("cannot create thumbnail for: " + subpath);
- console.error(err);
- });
-
- } else if (dirent.isDirectory()) {
- processFiles(subdir + '/' + dirent.name, width, height);
- }
- }
- dir.closeSync();
-}
diff --git a/assets/avatar.jpg b/assets/avatar.jpg
deleted file mode 100644
index e7b4fe4..0000000
Binary files a/assets/avatar.jpg and /dev/null differ
diff --git a/assets/style.scss b/assets/style.scss
deleted file mode 100644
index d3fd0ef..0000000
--- a/assets/style.scss
+++ /dev/null
@@ -1,5 +0,0 @@
----
----
-$baseurl: "{{site.url}}{{site.baseurl}}";
-
-@import "dogwood/initialize";
\ No newline at end of file
diff --git a/dogwood b/dogwood
new file mode 160000
index 0000000..6b90193
--- /dev/null
+++ b/dogwood
@@ -0,0 +1 @@
+Subproject commit 6b90193942f448bf92a9dd83c60ece0cb4f4c205
diff --git a/dogwood.gemspec b/dogwood.gemspec
deleted file mode 100644
index 7814252..0000000
--- a/dogwood.gemspec
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-Gem::Specification.new do |spec|
- spec.name = "osmus-dogwood"
- spec.version = "0.1.0"
- spec.authors = ["Quincy Morgan"]
- spec.email = ["2046746+quincylvania@users.noreply.github.com"]
-
- spec.summary = "The Jekyll theme powering openstreetmap.us"
- spec.homepage = "https://github.com/osmus/dogwood"
- spec.license = "MIT"
-
- spec.files = `git ls-files -z`.split("\x0").select do|f|
- f.match(%r!^((assets|_includes|_plugins|_layouts|_sass)/|_config.yml|index.html|(LICENSE|README)((\.(txt|md|markdown)|$)))!i)
- end
-
- spec.add_runtime_dependency "jekyll", "~> 4.3"
-
- spec.add_runtime_dependency "jekyll-archives", "~> 2.2.1"
- spec.add_runtime_dependency 'jekyll-include-cache', "~> 0.2.1"
-
- spec.add_runtime_dependency "absolute-urls"
- spec.add_runtime_dependency "post-aliases"
- spec.add_runtime_dependency "unwrap-img"
-end