diff --git a/components/groovy/com/jessebrault/site/lessons/LessonsBanner.groovy b/components/groovy/com/jessebrault/site/lessons/LessonsBanner.groovy new file mode 100644 index 0000000..58ae9cc --- /dev/null +++ b/components/groovy/com/jessebrault/site/lessons/LessonsBanner.groovy @@ -0,0 +1,17 @@ +package com.jessebrault.site.lessons + +import com.jessebrault.ssg.view.SkipTemplate +import groowt.view.View +import groowt.view.component.web.lib.DelegatingWebViewComponent + +@SkipTemplate +class LessonsBanner extends DelegatingWebViewComponent { + + private static final String lessonsBannerText = LessonsBanner.getResource('LessonsBanner.txt').text + + @Override + protected View getDelegate() { + return { Writer w -> w << lessonsBannerText } + } + +} diff --git a/components/groovy/com/jessebrault/site/util/OpenGraph.groovy b/components/groovy/com/jessebrault/site/util/OpenGraph.groovy index 349a050..6fe3981 100644 --- a/components/groovy/com/jessebrault/site/util/OpenGraph.groovy +++ b/components/groovy/com/jessebrault/site/util/OpenGraph.groovy @@ -20,7 +20,7 @@ class OpenGraph extends BaseWebViewComponent { OpenGraph(@Named('baseUrl') String baseUrl, @Global('openGraphFallbackImage') String fallbackImage, Map attr) { this.baseUrl = baseUrl title = attr.title - type = attr.type + type = attr.type ?: 'website' image = attr.image ?: fallbackImage description = attr.description path = attr.path diff --git a/components/groovy/com/jessebrault/site/videos/VideosBanner.groovy b/components/groovy/com/jessebrault/site/videos/VideosBanner.groovy new file mode 100644 index 0000000..11be608 --- /dev/null +++ b/components/groovy/com/jessebrault/site/videos/VideosBanner.groovy @@ -0,0 +1,17 @@ +package com.jessebrault.site.videos + +import com.jessebrault.ssg.view.SkipTemplate +import groowt.view.View +import groowt.view.component.web.lib.DelegatingWebViewComponent + +@SkipTemplate +class VideosBanner extends DelegatingWebViewComponent { + + private static final String videosBannerText = VideosBanner.getResource('VideosBanner.txt').text + + @Override + protected View getDelegate() { + return { Writer w -> w << videosBannerText } + } + +} diff --git a/components/resources/com/jessebrault/site/lessons/LessonsBanner.txt b/components/resources/com/jessebrault/site/lessons/LessonsBanner.txt new file mode 100644 index 0000000..1526616 --- /dev/null +++ b/components/resources/com/jessebrault/site/lessons/LessonsBanner.txt @@ -0,0 +1,11 @@ +
+
+ +
+ +
diff --git a/components/resources/com/jessebrault/site/videos/VideosBanner.txt b/components/resources/com/jessebrault/site/videos/VideosBanner.txt new file mode 100644 index 0000000..9fea3ba --- /dev/null +++ b/components/resources/com/jessebrault/site/videos/VideosBanner.txt @@ -0,0 +1,14 @@ + diff --git a/pages/groovy/com/jessebrault/site/lessons/LessonsPage.groovy b/pages/groovy/com/jessebrault/site/lessons/LessonsPage.groovy new file mode 100644 index 0000000..444428f --- /dev/null +++ b/pages/groovy/com/jessebrault/site/lessons/LessonsPage.groovy @@ -0,0 +1,37 @@ +package com.jessebrault.site.lessons + +import com.jessebrault.site.util.TitleMaker +import com.jessebrault.ssg.di.InjectText +import com.jessebrault.ssg.di.InjectTexts +import com.jessebrault.ssg.di.SelfPage +import com.jessebrault.ssg.page.Page +import com.jessebrault.ssg.page.PageSpec +import com.jessebrault.ssg.text.Text +import com.jessebrault.ssg.view.WvcPageView +import jakarta.inject.Inject + +@PageSpec(name = 'Lessons', path = '/lessons') +class LessonsPage extends WvcPageView { + + static final String description = 'Information about lessons offered by Jesse Brault.' + + final Page selfPage + private final TitleMaker titleMaker + private final Text lessonsText + + @Inject + LessonsPage(@SelfPage Page selfPage, TitleMaker titleMaker, @InjectText('/Lessons.md') Text lessonsText) { + this.selfPage = selfPage + this.titleMaker = titleMaker + this.lessonsText = lessonsText + } + + String getPageTitle() { + titleMaker.makeTitle(selfPage.name) + } + + String renderLessons() { + this.lessonsText.render() + } + +} diff --git a/pages/groovy/com/jessebrault/site/videos/VideosPage.groovy b/pages/groovy/com/jessebrault/site/videos/VideosPage.groovy new file mode 100644 index 0000000..6abdc4d --- /dev/null +++ b/pages/groovy/com/jessebrault/site/videos/VideosPage.groovy @@ -0,0 +1,37 @@ +package com.jessebrault.site.videos + +import com.jessebrault.site.util.TitleMaker +import com.jessebrault.ssg.di.InjectText +import com.jessebrault.ssg.di.InjectTexts +import com.jessebrault.ssg.di.SelfPage +import com.jessebrault.ssg.page.Page +import com.jessebrault.ssg.page.PageSpec +import com.jessebrault.ssg.text.Text +import com.jessebrault.ssg.view.WvcPageView +import jakarta.inject.Inject + +@PageSpec(name = 'Videos', path = '/videos') +class VideosPage extends WvcPageView { + + static final String description = 'Conducting videos of Jesse Brault.' + + final Page selfPage + private final TitleMaker titleMaker + private final Text videosText + + @Inject + VideosPage(@SelfPage Page selfPage, TitleMaker titleMaker, @InjectText('/Videos.md') Text videosText) { + this.selfPage = selfPage + this.titleMaker = titleMaker + this.videosText = videosText + } + + String getPageTitle() { + titleMaker.makeTitle(selfPage.name) + } + + String renderVideos() { + videosText.render() + } + +} diff --git a/pages/resources/com/jessebrault/site/lessons/LessonsPageTemplate.wvc b/pages/resources/com/jessebrault/site/lessons/LessonsPageTemplate.wvc new file mode 100644 index 0000000..844e949 --- /dev/null +++ b/pages/resources/com/jessebrault/site/lessons/LessonsPageTemplate.wvc @@ -0,0 +1,22 @@ +--- +package com.jessebrault.site.lessons + +import com.jessebrault.site.StandardPage +import com.jessebrault.site.util.OpenGraph +--- +} + banner={} +> +
+
+ <%= renderLessons() %> +
+
+
diff --git a/pages/resources/com/jessebrault/site/videos/VideosPageTemplate.wvc b/pages/resources/com/jessebrault/site/videos/VideosPageTemplate.wvc new file mode 100644 index 0000000..af76db4 --- /dev/null +++ b/pages/resources/com/jessebrault/site/videos/VideosPageTemplate.wvc @@ -0,0 +1,22 @@ +--- +package com.jessebrault.site.videos + +import com.jessebrault.site.StandardPage +import com.jessebrault.site.util.OpenGraph +--- +} + banner={} +> +
+
+ <%= renderVideos() %> +
+
+
diff --git a/ssg/default.groovy b/ssg/default.groovy index 87975b8..9e543ef 100644 --- a/ssg/default.groovy +++ b/ssg/default.groovy @@ -14,7 +14,7 @@ build { basePackage 'com.jessebrault.site' globals { siteTagLine = 'Conductor, Composer, Developer' - menuItems = ['Biography', 'Compositions', 'Contact'] + menuItems = ['Biography', 'Compositions', 'Videos', 'Lessons', 'Contact'] compositionCategories = ['Orchestra', 'Chamber', 'Solo', 'Wind Ensemble'] spotifyUrl = 'https://open.spotify.com/artist/4ea1gZnLlQTrXKIMsnlr45?si=DfR-KCDyTiycbjmYwu566w' youtubeUrl = 'https://www.youtube.com/@JesseBrault0709' diff --git a/static/main.css b/static/main.css index b0789cb..2d9f1cc 100644 --- a/static/main.css +++ b/static/main.css @@ -29,6 +29,7 @@ body { header { display: flex; + align-items: flex-end; justify-content: space-between; padding: 15px 25px; color: var(--off-white); @@ -36,7 +37,8 @@ header { header .titles { display: flex; - flex-direction: column; + align-items: baseline; + column-gap: 15px; } header .titles * { @@ -88,19 +90,22 @@ nav a:hover { color: var(--off-white); } -.banner { +.banner, +.landscape-banner { display: flex; flex-direction: column; align-items: center; + gap: 20px; + padding-bottom: 20px; color: var(--off-white); } -.banner > * { +:is(.banner, .landscape-banner) > * { width: 100%; } .banner-text { - padding: 25px; + padding-inline: 20px; letter-spacing: 0.1em; } @@ -137,6 +142,15 @@ article h3 { font-size: 1em; } +article ul { + padding-inline: 40px; + text-align: left; +} + +article ul li { + padding-block: 4px; +} + footer { display: flex; flex-direction: column; @@ -180,13 +194,15 @@ a:hover { color: rgba(from var(--petrol) r g b / 0.5); } -.headshot-container { +.headshot-container, +.landscape-photo-container { display: flex; flex-direction: column; align-items: center; } -.headshot { +.headshot, +.landscape-photo { width: 100%; } @@ -332,6 +348,19 @@ article.compositions { margin-block-start: 2em; } +#lessons-banner-text, +#videos-banner-text { + text-align: center; +} + +#videos-banner-text :is(a, a:visited) { + color: var(--light-gray); +} + +#videos-banner-text a:hover { + color: var(--off-white); +} + .contact-banner article.social-media-links { font-family: var(--gothic); } @@ -443,52 +472,32 @@ form.contact { color: red; } -@media screen and (max-width: 767px) { - nav ul { - position: absolute; - left: 0; - z-index: 1; - width: 100%; - display: none; - flex-direction: column; - align-items: center; - row-gap: 10px; - background-color: var(--petrol); - padding: 20px; - } -} - @media screen and (min-width: 768px) { html { font-size: 18px; } header { - display: flex; - align-items: baseline; - justify-content: space-between; padding-inline: 30px; } - nav .bars-wrapper { - display: none; + header .titles h2 { + display: unset; + font-size: 2em; + font-size: 18px; + letter-spacing: 0.15em; } - nav ul { - display: flex; - } - - .banner { + .banner, + .landscape-banner { flex-direction: unset; - } - - .banner > * { - padding: 15px 30px 30px; + padding: 0 30px 30px; + gap: 30px; } .banner-text { + padding-inline: unset; letter-spacing: 0.15em; - padding-top: 30px; } article h1 { @@ -553,10 +562,32 @@ form.contact { align-items: baseline; justify-content: space-between; } + + #lessons-banner-text, + #videos-banner-text { + font-size: 1.5em; + } +} + +@media screen and (max-width: 1023px) { + nav ul { + position: absolute; + left: 0; + z-index: 1; + width: 100%; + display: none; + flex-direction: column; + align-items: center; + row-gap: 10px; + padding: 20px; + background-color: var(--petrol); + border-bottom: 1px solid var(--charcoal); + } } @media screen and (min-width: 1024px) { header { + align-items: center; padding-inline: 50px; } @@ -565,9 +596,28 @@ form.contact { letter-spacing: 0.175em; } - .banner > * { - padding-inline: 50px; - padding-bottom: 50px; + header .titles h2 { + display: none; + } + + nav .bars-wrapper { + display: none; + } + + nav ul { + display: flex; + } + + .banner, + .landscape-banner { + padding: 0 50px 50px; + gap: 50px; + } + + .landscape-banner { + display: grid; + grid-template-columns: 1.5fr 1fr; + align-items: center; } footer { @@ -587,20 +637,16 @@ form.contact { .biography-banner .blurb-container button { display: unset; } + + #lessons-banner-text, + #videos-banner-text { + font-size: 2em; + } } @media screen and (min-width: 1200px) { - header .titles { - flex-direction: unset; - align-items: baseline; - column-gap: 15px; - } - header .titles h2 { display: unset; - font-size: 2em; - font-size: 18px; - letter-spacing: 0.15em; } .contact-banner svg { diff --git a/static/main.js b/static/main.js index 55f4756..d060add 100644 --- a/static/main.js +++ b/static/main.js @@ -2,7 +2,7 @@ window.addEventListener('load', function () { const navBars = document.getElementById('nav-bars') const navItems = document.getElementById('nav-items') navBars.addEventListener('click', function () { - if (window.matchMedia('screen and (max-width: 767px)').matches) { + if (window.matchMedia('screen and (max-width: 1023px)').matches) { if (navItems.style.display === 'flex') { navItems.style.display = 'none' } else { diff --git a/texts/Lessons.md b/texts/Lessons.md new file mode 100644 index 0000000..8ee31b2 --- /dev/null +++ b/texts/Lessons.md @@ -0,0 +1,11 @@ +# Lessons + +I offer remote lessons (as well as in-person lessons in Berlin, Germany) for the following subjects: + +- Music Theory +- Ear Training +- Music Composition +- Score Study +- Beginning and Intermediate Piano (in person in Berlin only) + +I offer flexible hourly rates. Please [contact](/contact) me to schedule your first lesson! diff --git a/texts/Videos.md b/texts/Videos.md new file mode 100644 index 0000000..a4e202a --- /dev/null +++ b/texts/Videos.md @@ -0,0 +1,11 @@ +# Conducting Videos + +Videos of the following works are available on YouTube: + +- [Beethoven: Symphony no. 4: II. Adagio](https://www.youtube.com/watch?v=QfqlwB8cnTA) +- [Brahms: Symphony no. 3: II. Andante](https://www.youtube.com/watch?v=Js8EXhM2kOQ) +- [Brahms: Symphony no. 4: IV. Allegro energico e passionato](https://www.youtube.com/watch?v=3gZl0NPuxOc) +- [Britten: Four Sea Interludes: II. Sunday Morning](https://www.youtube.com/watch?v=j9LUHck6B7M) +- [Debussy: Prélude à l'après-midi d'un Faune](https://www.youtube.com/watch?v=qMjjrYCfI8s) + +If you require additional video material, please [contact](/contact) me.