From a46fd988f5ae1328930f87112c64700a07a8e25a Mon Sep 17 00:00:00 2001 From: Asaf Gartner Date: Fri, 23 Jul 2021 06:09:46 +0300 Subject: [PATCH] Podcasts --- go.mod | 2 + go.sum | 7 +- public/style.css | 70 +- public/themes/dark/theme.css | 3 +- public/themes/light/theme.css | 3 +- src/hmnurl/hmnurl_test.go | 27 +- src/hmnurl/urls.go | 50 ++ src/initimage/initimage.go | 10 + src/main.go | 1 + ...2021-07-11T060838Z_RenamePodcastColumns.go | 53 ++ src/models/podcast.go | 31 + src/perf/perf.go | 10 +- src/rawdata/scss/_notices.scss | 35 + src/rawdata/scss/_projects.scss | 33 - src/rawdata/scss/style.scss | 1 + src/rawdata/scss/themes/dark/_variables.scss | 3 +- src/rawdata/scss/themes/light/_variables.scss | 3 +- src/templates/mapping.go | 40 ++ src/templates/src/include/notices.html | 5 + .../src/include/podcast_actions.html | 4 + src/templates/src/podcast.xml | 32 + src/templates/src/podcast_edit.html | 71 ++ src/templates/src/podcast_episode.html | 31 + src/templates/src/podcast_episode_edit.html | 23 + src/templates/src/podcast_index.html | 38 + src/templates/src/project_homepage.html | 6 +- src/templates/svg/appleinc.svg | 5 + src/templates/svg/google.svg | 5 + src/templates/svg/spotify.svg | 5 + src/templates/templates.go | 12 + src/templates/types.go | 27 + src/website/podcast.go | 679 ++++++++++++++++++ src/website/project_helper.go | 54 ++ src/website/projects.go | 31 +- src/website/requesthandling.go | 5 + src/website/routes.go | 15 +- 36 files changed, 1322 insertions(+), 108 deletions(-) create mode 100644 src/initimage/initimage.go create mode 100644 src/migration/migrations/2021-07-11T060838Z_RenamePodcastColumns.go create mode 100644 src/models/podcast.go create mode 100644 src/rawdata/scss/_notices.scss create mode 100644 src/templates/src/include/notices.html create mode 100644 src/templates/src/include/podcast_actions.html create mode 100644 src/templates/src/podcast.xml create mode 100644 src/templates/src/podcast_edit.html create mode 100644 src/templates/src/podcast_episode.html create mode 100644 src/templates/src/podcast_episode_edit.html create mode 100644 src/templates/src/podcast_index.html create mode 100755 src/templates/svg/appleinc.svg create mode 100755 src/templates/svg/google.svg create mode 100755 src/templates/svg/spotify.svg create mode 100644 src/website/podcast.go create mode 100644 src/website/project_helper.go diff --git a/go.mod b/go.mod index 7330a6cd..0fbb9c6d 100644 --- a/go.mod +++ b/go.mod @@ -19,11 +19,13 @@ require ( github.com/rs/zerolog v1.21.0 github.com/spf13/cobra v1.1.3 github.com/stretchr/testify v1.7.0 + github.com/tcolgate/mp3 v0.0.0-20170426193717-e79c5a46d300 github.com/teacat/noire v1.1.0 github.com/wellington/go-libsass v0.9.2 github.com/yuin/goldmark v1.4.1 github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 + golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d ) replace ( diff --git a/go.sum b/go.sum index 30e9d4bd..3a65a872 100644 --- a/go.sum +++ b/go.sum @@ -298,6 +298,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tcolgate/mp3 v0.0.0-20170426193717-e79c5a46d300 h1:XQdibLKagjdevRB6vAjVY4qbSr8rQ610YzTkWcxzxSI= +github.com/tcolgate/mp3 v0.0.0-20170426193717-e79c5a46d300/go.mod h1:FNa/dfN95vAYCNFrIKRrlRo+MBLbwmR9Asa5f2ljmBI= github.com/teacat/noire v1.1.0 h1:5IgJ1H8jodiSSYnrVadV2JjbAnEgCCjYUQxSUuaQ7Sg= github.com/teacat/noire v1.1.0/go.mod h1:cetGlnqr+9yKJcFgRgYXOWJY66XIrrjUsGBwNlNNtAk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -340,6 +342,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -409,8 +413,9 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/public/style.css b/public/style.css index 3d0b8df7..4c5d87bc 100644 --- a/public/style.css +++ b/public/style.css @@ -9212,15 +9212,6 @@ span.icon-rss::before { padding: 0px; min-height: 0em; } -.project .notice { - color: #fff; - color: var(--project-notice-text-color); } - .project .notice a { - color: #fff; - color: var(--project-notice-text-color); - border-bottom-color: #fff; - border-bottom-color: var(--project-notice-text-color); } - .project .pair { display: flex; align-items: flex-start; } @@ -9264,30 +9255,6 @@ span.icon-rss::before { .project .forum .thread-entry-right { display: none; } -.notice-unapproved { - background-color: #b42222; - background-color: var(--notice-unapproved-color); } - -.notice-hidden { - background-color: #b6b6b6; - background-color: var(--notice-hidden-color); } - -.notice-hiatus { - background-color: #aa7d30; - background-color: var(--notice-hiatus-color); } - -.notice-dead { - background-color: #b42222; - background-color: var(--notice-dead-color); } - -.notice-lts { - background-color: #43a52f; - background-color: var(--notice-lts-color); } - -.notice-lts-reqd { - background-color: #aa7d30; - background-color: var(--notice-lts-reqd-color); } - .project-card { color: black; color: var(--fg-font-color); @@ -9546,3 +9513,40 @@ span.icon-rss::before { .carousel-container .carousel-button.active:hover { background-color: #ccc; background-color: var(--theme-color-dimmest); } + +.notice { + color: #fff; + color: var(--notice-text-color); } + .notice a { + color: #fff; + color: var(--notice-text-color); + border-bottom-color: #fff; + border-bottom-color: var(--notice-text-color); } + +.notice-unapproved { + background-color: #b42222; + background-color: var(--notice-unapproved-color); } + +.notice-hidden { + background-color: #b6b6b6; + background-color: var(--notice-hidden-color); } + +.notice-hiatus { + background-color: #aa7d30; + background-color: var(--notice-hiatus-color); } + +.notice-dead { + background-color: #b42222; + background-color: var(--notice-dead-color); } + +.notice-lts { + background-color: #43a52f; + background-color: var(--notice-lts-color); } + +.notice-lts-reqd { + background-color: #aa7d30; + background-color: var(--notice-lts-reqd-color); } + +.notice-success { + background-color: #43a52f; + background-color: var(--notice-success-color); } diff --git a/public/themes/dark/theme.css b/public/themes/dark/theme.css index c8a4dd41..fac0109d 100644 --- a/public/themes/dark/theme.css +++ b/public/themes/dark/theme.css @@ -234,19 +234,20 @@ will throw an error. --text-background: #181818; --spoiler-border: #777; --background-even-background: #242424; - --project-notice-text-color: #eee; --project-card-border-color: #333; --project-user-suggestions-background: #222; --project-user-suggestions-border-color: #444; --project-edit-logo-previw-border-color: #444; --project-edit-quota-bar-border-color: #444; --project-edit-quota-bar-filled-background: #888; + --notice-text-color: #eee; --notice-unapproved-color: #7a2020; --notice-hidden-color: #494949; --notice-hiatus-color: #876327; --notice-dead-color: #7a2020; --notice-lts-color: #2a681d; --notice-lts-reqd-color: #876327; + --notice-success-color: #2a681d; --optionbar-border-color: #333; --tab-background: #181818; --tab-border-color: #3f3f3f; diff --git a/public/themes/light/theme.css b/public/themes/light/theme.css index f22af402..0e55f35f 100644 --- a/public/themes/light/theme.css +++ b/public/themes/light/theme.css @@ -252,19 +252,20 @@ will throw an error. --text-background: #f9f9f9; --spoiler-border: #aaa; --background-even-background: #f8f8f8; - --project-notice-text-color: #fff; --project-card-border-color: #aaa; --project-user-suggestions-background: #fff; --project-user-suggestions-border-color: #ddd; --project-edit-logo-previw-border-color: #999; --project-edit-quota-bar-border-color: #999; --project-edit-quota-bar-filled-background: #444; + --notice-text-color: #fff; --notice-unapproved-color: #b42222; --notice-hidden-color: #b6b6b6; --notice-hiatus-color: #aa7d30; --notice-dead-color: #b42222; --notice-lts-color: #43a52f; --notice-lts-reqd-color: #aa7d30; + --notice-success-color: #43a52f; --optionbar-border-color: #ccc; --tab-background: #fff; --tab-border-color: #d8d8d8; diff --git a/src/hmnurl/hmnurl_test.go b/src/hmnurl/hmnurl_test.go index b14cecb0..d587caee 100644 --- a/src/hmnurl/hmnurl_test.go +++ b/src/hmnurl/hmnurl_test.go @@ -85,7 +85,7 @@ func TestUserProfile(t *testing.T) { } func TestSnippet(t *testing.T) { - AssetRegexMatch(t, BuildSnippet(15), RegexSnippet, map[string]string{"snippetid": "15"}) + AssertRegexMatch(t, BuildSnippet(15), RegexSnippet, map[string]string{"snippetid": "15"}) } func TestFeed(t *testing.T) { @@ -123,6 +123,28 @@ func TestPodcast(t *testing.T) { AssertSubdomain(t, BuildPodcast("hero"), "hero") } +func TestPodcastEdit(t *testing.T) { + AssertRegexMatch(t, BuildPodcastEdit(""), RegexPodcastEdit, nil) + AssertRegexMatch(t, BuildPodcastEditSuccess(""), RegexPodcastEdit, nil) +} + +func TestPodcastEpisode(t *testing.T) { + AssertRegexMatch(t, BuildPodcastEpisode("", "test"), RegexPodcastEpisode, map[string]string{"episodeid": "test"}) +} + +func TestPodcastEpisodeNew(t *testing.T) { + AssertRegexMatch(t, BuildPodcastEpisodeNew(""), RegexPodcastEpisodeNew, nil) +} + +func TestPodcastEpisodeEdit(t *testing.T) { + AssertRegexMatch(t, BuildPodcastEpisodeEdit("", "test"), RegexPodcastEpisodeEdit, map[string]string{"episodeid": "test"}) + AssertRegexMatch(t, BuildPodcastEpisodeEditSuccess("", "test"), RegexPodcastEpisodeEdit, map[string]string{"episodeid": "test"}) +} + +func TestPodcastRSS(t *testing.T) { + AssertRegexMatch(t, BuildPodcastRSS(""), RegexPodcastRSS, nil) +} + func TestForumCategory(t *testing.T) { AssertRegexMatch(t, BuildForumCategory("", nil, 1), RegexForumCategory, nil) AssertRegexMatch(t, BuildForumCategory("", []string{"wip"}, 2), RegexForumCategory, map[string]string{"cats": "wip", "page": "2"}) @@ -137,7 +159,8 @@ func TestForumCategory(t *testing.T) { } func TestForumNewThread(t *testing.T) { - AssertRegexMatch(t, BuildForumNewThread("", []string{"sub", "wip"}), RegexForumNewThread, map[string]string{"cats": "sub/wip"}) + AssertRegexMatch(t, BuildForumNewThread("", []string{"sub", "wip"}, false), RegexForumNewThread, map[string]string{"cats": "sub/wip"}) + AssertRegexMatch(t, BuildForumNewThread("", []string{"sub", "wip"}, true), RegexForumNewThreadSubmit, map[string]string{"cats": "sub/wip"}) } func TestForumThread(t *testing.T) { diff --git a/src/hmnurl/urls.go b/src/hmnurl/urls.go index 3cb9360b..5be07186 100644 --- a/src/hmnurl/urls.go +++ b/src/hmnurl/urls.go @@ -251,6 +251,56 @@ func BuildPodcast(projectSlug string) string { return ProjectUrl("/podcast", nil, projectSlug) } +var RegexPodcastEdit = regexp.MustCompile(`^/podcast/edit$`) + +func BuildPodcastEdit(projectSlug string) string { + defer CatchPanic() + return ProjectUrl("/podcast/edit", nil, projectSlug) +} + +func BuildPodcastEditSuccess(projectSlug string) string { + defer CatchPanic() + return ProjectUrl("/podcast/edit", []Q{Q{"success", "true"}}, projectSlug) +} + +var RegexPodcastEpisode = regexp.MustCompile(`^/podcast/ep/(?P[^/]+)$`) + +func BuildPodcastEpisode(projectSlug string, episodeGUID string) string { + defer CatchPanic() + return ProjectUrl(fmt.Sprintf("/podcast/ep/%s", episodeGUID), nil, projectSlug) +} + +var RegexPodcastEpisodeNew = regexp.MustCompile(`^/podcast/ep/new$`) + +func BuildPodcastEpisodeNew(projectSlug string) string { + defer CatchPanic() + return ProjectUrl("/podcast/ep/new", nil, projectSlug) +} + +var RegexPodcastEpisodeEdit = regexp.MustCompile(`^/podcast/ep/(?P[^/]+)/edit$`) + +func BuildPodcastEpisodeEdit(projectSlug string, episodeGUID string) string { + defer CatchPanic() + return ProjectUrl(fmt.Sprintf("/podcast/ep/%s/edit", episodeGUID), nil, projectSlug) +} + +func BuildPodcastEpisodeEditSuccess(projectSlug string, episodeGUID string) string { + defer CatchPanic() + return ProjectUrl(fmt.Sprintf("/podcast/ep/%s/edit", episodeGUID), []Q{Q{"success", "true"}}, projectSlug) +} + +var RegexPodcastRSS = regexp.MustCompile(`^/podcast/podcast.xml$`) + +func BuildPodcastRSS(projectSlug string) string { + defer CatchPanic() + return ProjectUrl("/podcast/podcast.xml", nil, projectSlug) +} + +func BuildPodcastEpisodeFile(projectSlug string, filename string) string { + defer CatchPanic() + return BuildUserFile(fmt.Sprintf("podcast/%s/%s", projectSlug, filename)) +} + /* * Forums */ diff --git a/src/initimage/initimage.go b/src/initimage/initimage.go new file mode 100644 index 00000000..a25afd69 --- /dev/null +++ b/src/initimage/initimage.go @@ -0,0 +1,10 @@ +package initimage + +import ( + _ "golang.org/x/image/bmp" + _ "golang.org/x/image/tiff" + _ "golang.org/x/image/webp" // NOTE(asaf): webp handles vp8 and vp8l + _ "image/gif" + _ "image/jpeg" + _ "image/png" +) diff --git a/src/main.go b/src/main.go index e3ccc3b8..6bfb901b 100644 --- a/src/main.go +++ b/src/main.go @@ -3,6 +3,7 @@ package main import ( _ "git.handmade.network/hmn/hmn/src/admintools" _ "git.handmade.network/hmn/hmn/src/buildscss" + _ "git.handmade.network/hmn/hmn/src/initimage" _ "git.handmade.network/hmn/hmn/src/migration" "git.handmade.network/hmn/hmn/src/website" ) diff --git a/src/migration/migrations/2021-07-11T060838Z_RenamePodcastColumns.go b/src/migration/migrations/2021-07-11T060838Z_RenamePodcastColumns.go new file mode 100644 index 00000000..a72e3195 --- /dev/null +++ b/src/migration/migrations/2021-07-11T060838Z_RenamePodcastColumns.go @@ -0,0 +1,53 @@ +package migrations + +import ( + "context" + "time" + + "git.handmade.network/hmn/hmn/src/migration/types" + "git.handmade.network/hmn/hmn/src/oops" + "github.com/jackc/pgx/v4" +) + +func init() { + registerMigration(RenamePodcastColumns{}) +} + +type RenamePodcastColumns struct{} + +func (m RenamePodcastColumns) Version() types.MigrationVersion { + return types.MigrationVersion(time.Date(2021, 7, 11, 6, 8, 38, 0, time.UTC)) +} + +func (m RenamePodcastColumns) Name() string { + return "RenamePodcastColumns" +} + +func (m RenamePodcastColumns) Description() string { + return "Rename columns to lowercase" +} + +func (m RenamePodcastColumns) Up(ctx context.Context, tx pgx.Tx) error { + _, err := tx.Exec(ctx, ` + ALTER TABLE handmade_podcastepisode + RENAME COLUMN "enclosureFile" TO "audio_filename"; + + ALTER TABLE handmade_podcastepisode + RENAME COLUMN "pubDate" TO "pub_date"; + + ALTER TABLE handmade_podcastepisode + RENAME COLUMN "episodeNumber" TO "episode_number"; + + ALTER TABLE handmade_podcastepisode + RENAME COLUMN "seasonNumber" TO "season_number"; + `) + if err != nil { + return oops.New(err, "failed to rename podcast episode columns") + } + + return nil +} + +func (m RenamePodcastColumns) Down(ctx context.Context, tx pgx.Tx) error { + panic("Implement me") +} diff --git a/src/models/podcast.go b/src/models/podcast.go new file mode 100644 index 00000000..6c1b9aea --- /dev/null +++ b/src/models/podcast.go @@ -0,0 +1,31 @@ +package models + +import ( + "time" + + "github.com/google/uuid" +) + +type Podcast struct { + ID int `db:"id"` + ImageID int `db:"image_id"` + ProjectID int `db:"project_id"` + + Title string `db:"title"` + Description string `db:"description"` + Language string `db:"language"` +} + +type PodcastEpisode struct { + GUID uuid.UUID `db:"guid"` + PodcastID int `db:"podcast_id"` + + Title string `db:"title"` + Description string `db:"description"` + DescriptionHtml string `db:"description_rendered"` + AudioFile string `db:"audio_filename"` + PublicationDate time.Time `db:"pub_date"` + Duration int `db:"duration"` // NOTE(asaf): In seconds + EpisodeNumber int `db:"episode_number"` + SeasonNumber *int `db:"season_number"` // TODO(asaf): Do we need this?? +} diff --git a/src/perf/perf.go b/src/perf/perf.go index b374b395..018bb91b 100644 --- a/src/perf/perf.go +++ b/src/perf/perf.go @@ -8,16 +8,18 @@ import ( type RequestPerf struct { Route string Path string // the path actually matched + Method string Start time.Time End time.Time Blocks []PerfBlock } -func MakeNewRequestPerf(route string, path string) *RequestPerf { +func MakeNewRequestPerf(route string, method string, path string) *RequestPerf { return &RequestPerf{ - Start: time.Now(), - Route: route, - Path: path, + Start: time.Now(), + Route: route, + Path: path, + Method: method, } } diff --git a/src/rawdata/scss/_notices.scss b/src/rawdata/scss/_notices.scss new file mode 100644 index 00000000..e4c20f00 --- /dev/null +++ b/src/rawdata/scss/_notices.scss @@ -0,0 +1,35 @@ +.notice { + @include usevar(color, notice-text-color); + + a { + @include usevar(color, notice-text-color); + @include usevar(border-bottom-color, notice-text-color); + } +} +.notice-unapproved { + @include usevar(background-color, notice-unapproved-color); +} + +.notice-hidden { + @include usevar(background-color, notice-hidden-color); +} + +.notice-hiatus { + @include usevar(background-color, notice-hiatus-color); +} + +.notice-dead { + @include usevar(background-color, notice-dead-color); +} + +.notice-lts { + @include usevar(background-color, notice-lts-color); +} + +.notice-lts-reqd { + @include usevar(background-color, notice-lts-reqd-color); +} + +.notice-success { + @include usevar(background-color, notice-success-color); +} diff --git a/src/rawdata/scss/_projects.scss b/src/rawdata/scss/_projects.scss index 09f04440..046ad7a2 100644 --- a/src/rawdata/scss/_projects.scss +++ b/src/rawdata/scss/_projects.scss @@ -1,13 +1,4 @@ .project { - .notice { - @include usevar(color, project-notice-text-color); - - a { - @include usevar(color, project-notice-text-color); - @include usevar(border-bottom-color, project-notice-text-color); - } - } - .pair { display: flex; align-items: flex-start; @@ -69,30 +60,6 @@ } } -.notice-unapproved { - @include usevar(background-color, notice-unapproved-color); -} - -.notice-hidden { - @include usevar(background-color, notice-hidden-color); -} - -.notice-hiatus { - @include usevar(background-color, notice-hiatus-color); -} - -.notice-dead { - @include usevar(background-color, notice-dead-color); -} - -.notice-lts { - @include usevar(background-color, notice-lts-color); -} - -.notice-lts-reqd { - @include usevar(background-color, notice-lts-reqd-color); -} - .project-card { @include usevar(color, 'fg-font-color'); @include usevar(background-color, 'card-background'); diff --git a/src/rawdata/scss/style.scss b/src/rawdata/scss/style.scss index 17733b29..617e220c 100644 --- a/src/rawdata/scss/style.scss +++ b/src/rawdata/scss/style.scss @@ -24,3 +24,4 @@ @import 'streams'; @import 'timeline'; @import 'carousel'; +@import 'notices'; diff --git a/src/rawdata/scss/themes/dark/_variables.scss b/src/rawdata/scss/themes/dark/_variables.scss index 9b969f78..8c567d90 100644 --- a/src/rawdata/scss/themes/dark/_variables.scss +++ b/src/rawdata/scss/themes/dark/_variables.scss @@ -35,7 +35,6 @@ $vars: ( background-even-background: #242424, - project-notice-text-color: $fg-font-color, project-card-border-color: #333, project-user-suggestions-background: #222, project-user-suggestions-border-color: #444, @@ -43,12 +42,14 @@ $vars: ( project-edit-quota-bar-border-color: #444, project-edit-quota-bar-filled-background: #888, + notice-text-color: $fg-font-color, notice-unapproved-color: #7a2020, notice-hidden-color: #494949, notice-hiatus-color: #876327, notice-dead-color: #7a2020, notice-lts-color: #2a681d, notice-lts-reqd-color: #876327, + notice-success-color: #2a681d, optionbar-border-color: #333, diff --git a/src/rawdata/scss/themes/light/_variables.scss b/src/rawdata/scss/themes/light/_variables.scss index 53ce00e8..634f3683 100644 --- a/src/rawdata/scss/themes/light/_variables.scss +++ b/src/rawdata/scss/themes/light/_variables.scss @@ -35,7 +35,6 @@ $vars: ( background-even-background: #f8f8f8, - project-notice-text-color: #fff, project-card-border-color: #aaa, project-user-suggestions-background: #fff, project-user-suggestions-border-color: #ddd, @@ -43,12 +42,14 @@ $vars: ( project-edit-quota-bar-border-color: #999, project-edit-quota-bar-filled-background: #444, + notice-text-color: #fff, notice-unapproved-color: #b42222, notice-hidden-color: #b6b6b6, notice-hiatus-color: #aa7d30, notice-dead-color: #b42222, notice-lts-color: #43a52f, notice-lts-reqd-color: #aa7d30, + notice-success-color: #43a52f, optionbar-border-color: #ccc, diff --git a/src/templates/mapping.go b/src/templates/mapping.go index a7df12b0..3602547b 100644 --- a/src/templates/mapping.go +++ b/src/templates/mapping.go @@ -304,6 +304,46 @@ func TimelineItemsToJSON(items []TimelineItem) string { return builder.String() } +func PodcastToTemplate(projectSlug string, podcast *models.Podcast, imageFilename string) Podcast { + imageUrl := "" + if imageFilename != "" { + imageUrl = hmnurl.BuildUserFile(imageFilename) + } + return Podcast{ + Title: podcast.Title, + Description: podcast.Description, + Language: podcast.Language, + ImageUrl: imageUrl, + Url: hmnurl.BuildPodcast(projectSlug), + + RSSUrl: hmnurl.BuildPodcastRSS(projectSlug), + // TODO(asaf): Move this to the db if we want to support user podcasts + AppleUrl: "https://podcasts.apple.com/us/podcast/the-handmade-network-podcast/id1507790631", + GoogleUrl: "https://www.google.com/podcasts?feed=aHR0cHM6Ly9oYW5kbWFkZS5uZXR3b3JrL3BvZGNhc3QvcG9kY2FzdC54bWw%3D", + SpotifyUrl: "https://open.spotify.com/show/2Nd9NjXscrBbQwYULiYKiU", + } +} + +func PodcastEpisodeToTemplate(projectSlug string, episode *models.PodcastEpisode, audioFileSize int64, imageFilename string) PodcastEpisode { + imageUrl := "" + if imageFilename != "" { + imageUrl = hmnurl.BuildUserFile(imageFilename) + } + return PodcastEpisode{ + GUID: episode.GUID.String(), + Title: episode.Title, + Description: episode.Description, + DescriptionHtml: template.HTML(episode.DescriptionHtml), + EpisodeNumber: episode.EpisodeNumber, + Url: hmnurl.BuildPodcastEpisode(projectSlug, episode.GUID.String()), + ImageUrl: imageUrl, + FileUrl: hmnurl.BuildPodcastEpisodeFile(projectSlug, episode.AudioFile), + FileSize: audioFileSize, + PublicationDate: episode.PublicationDate, + Duration: episode.Duration, + } +} + func maybeString(s *string) string { if s == nil { return "" diff --git a/src/templates/src/include/notices.html b/src/templates/src/include/notices.html new file mode 100644 index 00000000..4c08134d --- /dev/null +++ b/src/templates/src/include/notices.html @@ -0,0 +1,5 @@ +{{ range . }} +
+ {{ .Content }} +
+{{ end }} diff --git a/src/templates/src/include/podcast_actions.html b/src/templates/src/include/podcast_actions.html new file mode 100644 index 00000000..e79a3f0c --- /dev/null +++ b/src/templates/src/include/podcast_actions.html @@ -0,0 +1,4 @@ +4 Subscribe +{{ svg "appleinc" }} Apple Podcasts +{{ svg "google" }} Google Podcasts +{{ svg "spotify" }} Spotify diff --git a/src/templates/src/podcast.xml b/src/templates/src/podcast.xml new file mode 100644 index 00000000..1bc407f1 --- /dev/null +++ b/src/templates/src/podcast.xml @@ -0,0 +1,32 @@ +{{ noescape "" }} + + + + {{ .Podcast.Title }} + {{ .Podcast.Url }} + {{ .Podcast.Language }} + © 2021 The Handmade Network{{/* TODO(asaf): Change this in case we want to allow user podcasts */}} + The Handmade Network + + The Handmade Network + team@handmadedev.org + + {{ .Podcast.Description }} + + + false + {{ range .Episodes }} + + {{ .GUID }} + {{ .Title }} + {{ .Description }} + {{ .EpisodeNumber }} + {{ .EpisodeNumber }} + + {{ .PublicationDate }} + {{ .Duration }} + {{ .Url }} + + {{ end }} + + diff --git a/src/templates/src/podcast_edit.html b/src/templates/src/podcast_edit.html new file mode 100644 index 00000000..dbcda7f6 --- /dev/null +++ b/src/templates/src/podcast_edit.html @@ -0,0 +1,71 @@ +{{ template "base.html" . }} + +{{ define "content" }} +
+ {{ template "notices.html" .Notices }} +
+ {{ csrftoken .Session }} + + +
+ + + Reset Image + +
+
+ +
+ +
+
+ +{{ end }} diff --git a/src/templates/src/podcast_episode.html b/src/templates/src/podcast_episode.html new file mode 100644 index 00000000..34e50957 --- /dev/null +++ b/src/templates/src/podcast_episode.html @@ -0,0 +1,31 @@ +{{ template "base.html" . }} + +{{ define "content" }} +
+
+

Episode {{ .Episode.EpisodeNumber }}: {{ .Episode.Title }}

+
+ {{ template "podcast_actions.html" .Podcast }} + {{ with .EditUrl }} + ✎ Edit Episode + {{ end }} +
+ +
+
+ +
+ Download +
+
+
+ +
+
+ +
+ {{ .Episode.DescriptionHtml }} +
+
+
+{{ end }} diff --git a/src/templates/src/podcast_episode_edit.html b/src/templates/src/podcast_episode_edit.html new file mode 100644 index 00000000..ccdedaa8 --- /dev/null +++ b/src/templates/src/podcast_episode_edit.html @@ -0,0 +1,23 @@ +{{ template "base.html" . }} + +{{ define "content" }} +
+ {{ template "notices.html" .Notices }} +

{{ if .IsEdit }}Edit{{ else }}New{{ end }} Episode

+
+ {{ csrftoken .Session }} + + + + +
+ +
+
+
+{{ end }} diff --git a/src/templates/src/podcast_index.html b/src/templates/src/podcast_index.html new file mode 100644 index 00000000..d5874b68 --- /dev/null +++ b/src/templates/src/podcast_index.html @@ -0,0 +1,38 @@ +{{ template "base.html" . }} + +{{ define "extrahead" }} + +{{ end }} + +{{ define "content" }} +
+
+

{{ .Podcast.Title }}

+
+ {{ template "podcast_actions.html" .Podcast }} + {{ with .EditUrl }} + ✎ Edit Podcast + {{ end }} + {{ with .NewEpisodeUrl }} + + New Episode + {{ end }} +
+ +

{{ .Podcast.Description }}

+ + +
+
+{{ end }} diff --git a/src/templates/src/project_homepage.html b/src/templates/src/project_homepage.html index f0027988..9a5f1192 100644 --- a/src/templates/src/project_homepage.html +++ b/src/templates/src/project_homepage.html @@ -9,11 +9,7 @@ {{ define "content" }}
- {{ range .Notices }} -
- {{ .Content }} -
- {{ end }} + {{ template "notices.html" .Notices }} {{ with .Screenshots }}