Do jam showcase stuff
This commit is contained in:
parent
776c78913a
commit
251446d6e4
|
@ -76,6 +76,7 @@ type DiscordConfig struct {
|
|||
MemberRoleID string
|
||||
ShowcaseChannelID string
|
||||
LibraryChannelID string
|
||||
JamShowcaseChannelID string
|
||||
}
|
||||
|
||||
type EpisodeGuide struct {
|
||||
|
|
|
@ -582,7 +582,7 @@ func (bot *botInstance) messageCreateOrUpdate(ctx context.Context, msg *Message)
|
|||
}
|
||||
|
||||
if msg.ChannelID == config.Config.Discord.ShowcaseChannelID {
|
||||
err := bot.processShowcaseMsg(ctx, msg)
|
||||
err := bot.processShowcaseMsg(ctx, msg, false)
|
||||
if err != nil {
|
||||
logging.ExtractLogger(ctx).Error().Err(err).Msg("failed to process showcase message")
|
||||
return nil
|
||||
|
@ -590,6 +590,15 @@ func (bot *botInstance) messageCreateOrUpdate(ctx context.Context, msg *Message)
|
|||
return nil
|
||||
}
|
||||
|
||||
if msg.ChannelID == config.Config.Discord.JamShowcaseChannelID {
|
||||
err := bot.processShowcaseMsg(ctx, msg, true)
|
||||
if err != nil {
|
||||
logging.ExtractLogger(ctx).Error().Err(err).Msg("failed to process jam showcase message")
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if msg.ChannelID == config.Config.Discord.LibraryChannelID {
|
||||
err := bot.processLibraryMsg(ctx, msg)
|
||||
if err != nil {
|
||||
|
|
|
@ -25,7 +25,8 @@ var reDiscordMessageLink = regexp.MustCompile(`https?://.+?(\s|$)`)
|
|||
|
||||
var errNotEnoughInfo = errors.New("Discord didn't send enough info in this event for us to do this")
|
||||
|
||||
func (bot *botInstance) processShowcaseMsg(ctx context.Context, msg *Message) error {
|
||||
// TODO: Turn this ad-hoc isJam parameter into a tag or something
|
||||
func (bot *botInstance) processShowcaseMsg(ctx context.Context, msg *Message, isJam bool) error {
|
||||
switch msg.Type {
|
||||
case MessageTypeDefault, MessageTypeReply, MessageTypeApplicationCommand:
|
||||
default:
|
||||
|
@ -57,10 +58,17 @@ func (bot *botInstance) processShowcaseMsg(ctx context.Context, msg *Message) er
|
|||
return err
|
||||
}
|
||||
if doSnippet, err := AllowedToCreateMessageSnippet(ctx, tx, newMsg.UserID); doSnippet && err == nil {
|
||||
_, err := CreateMessageSnippet(ctx, tx, msg.ID)
|
||||
snippet, err := CreateMessageSnippet(ctx, tx, msg.ID)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to create snippet in gateway")
|
||||
}
|
||||
|
||||
if isJam {
|
||||
_, err := tx.Exec(ctx, `UPDATE handmade_snippet SET is_jam = TRUE WHERE id = $1`, snippet.ID)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to mark snippet as a jam snippet")
|
||||
}
|
||||
}
|
||||
} else if err != nil {
|
||||
return oops.New(err, "failed to check snippet permissions in gateway")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
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(AddJamSnippetField{})
|
||||
}
|
||||
|
||||
type AddJamSnippetField struct{}
|
||||
|
||||
func (m AddJamSnippetField) Version() types.MigrationVersion {
|
||||
return types.MigrationVersion(time.Date(2021, 9, 25, 2, 38, 10, 0, time.UTC))
|
||||
}
|
||||
|
||||
func (m AddJamSnippetField) Name() string {
|
||||
return "AddJamSnippetField"
|
||||
}
|
||||
|
||||
func (m AddJamSnippetField) Description() string {
|
||||
return "Add a special field for jam snippets"
|
||||
}
|
||||
|
||||
func (m AddJamSnippetField) Up(ctx context.Context, tx pgx.Tx) error {
|
||||
_, err := tx.Exec(ctx, `
|
||||
ALTER TABLE handmade_snippet
|
||||
ADD is_jam BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
`)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to add jam column")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m AddJamSnippetField) Down(ctx context.Context, tx pgx.Tx) error {
|
||||
_, err := tx.Exec(ctx, `
|
||||
ALTER TABLE handmade_snippet
|
||||
DROP is_jam;
|
||||
`)
|
||||
if err != nil {
|
||||
return oops.New(err, "failed to drop jam column")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -22,12 +22,19 @@
|
|||
<title>Handmade Network</title>
|
||||
{{ end }}
|
||||
|
||||
<script src="{{ static "js/templates.js" }}"></script>
|
||||
<script src="{{ static "js/showcase.js" }}"></script>
|
||||
|
||||
<link rel="stylesheet" href="{{ static "fonts/mohave/stylesheet.css" }}">
|
||||
<link href='https://fonts.googleapis.com/css?family=Fira+Sans:300,400,500,600' rel='stylesheet' type='text/css'>
|
||||
<link href='https://fonts.googleapis.com/css?family=Fira+Mono:300,400,500,700' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" type="text/css" href="{{ static "style.css" }}">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--content-background: #f8f8f8;
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(#ab4c47, #a5467d);
|
||||
}
|
||||
|
@ -171,6 +178,11 @@
|
|||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.showcase-item {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 30em) {
|
||||
/* not small styles */
|
||||
|
||||
|
@ -256,6 +268,16 @@
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div id="showcase-outer-container" class="bg-black-20 pt4 pb3 pb4-ns">
|
||||
<div class="section mw8 margin-center ph3 ph4-l">
|
||||
<h2>Happening right now.</h2>
|
||||
<p>
|
||||
The jam is underway! These screenshots and videos were shared in #jam-showcase on our <a href="https://discord.gg/hxWxDee" target="_blank">Discord</a>. Join us!
|
||||
</p>
|
||||
<div id="showcase-container" class="mw8 center-layout mh2 mh0-ns"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section flex-fair mw8 margin-center ph3 ph4-l mv4">
|
||||
<h2>Why reinvent the wheel?</h2>
|
||||
<p>
|
||||
|
@ -346,6 +368,106 @@
|
|||
{{ template "footer.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ template "showcase_templates.html" }}
|
||||
|
||||
<!-- Copy-pasted and mangled from showcase.html -->
|
||||
<script>
|
||||
const ROW_HEIGHT = 300;
|
||||
const ITEM_SPACING = 4;
|
||||
|
||||
const showcaseItems = JSON.parse("{{ .ShowcaseItemsJSON }}");
|
||||
const addThumbnailFuncs = new Array(showcaseItems.length);
|
||||
|
||||
const showcaseOuterContainer = document.querySelector('#showcase-outer-container');
|
||||
let showcaseContainer = document.querySelector('#showcase-container');
|
||||
|
||||
showcaseOuterContainer.classList.toggle('dn', showcaseItems.length === 0);
|
||||
|
||||
const itemElements = []; // array of arrays
|
||||
for (let i = 0; i < showcaseItems.length; i++) {
|
||||
const item = showcaseItems[i];
|
||||
|
||||
const [itemEl, addThumbnail] = makeShowcaseItem(item);
|
||||
itemEl.container.setAttribute('data-index', i);
|
||||
itemEl.container.setAttribute('data-date', item.date);
|
||||
|
||||
addThumbnailFuncs[i] = addThumbnail;
|
||||
|
||||
itemElements.push(itemEl.container);
|
||||
}
|
||||
|
||||
function layout() {
|
||||
const width = showcaseContainer.getBoundingClientRect().width;
|
||||
showcaseContainer = emptyElement(showcaseContainer);
|
||||
|
||||
function addRow(itemEls, rowWidth, container) {
|
||||
const totalSpacing = ITEM_SPACING * (itemEls.length - 1);
|
||||
const scaleFactor = (width / Math.max(rowWidth, width));
|
||||
|
||||
const row = document.createElement('div');
|
||||
row.classList.add('flex');
|
||||
row.classList.toggle('justify-between', rowWidth >= width);
|
||||
row.style.marginBottom = `${ITEM_SPACING}px`;
|
||||
|
||||
for (const itemEl of itemEls) {
|
||||
const index = parseInt(itemEl.getAttribute('data-index'), 10);
|
||||
const item = showcaseItems[index];
|
||||
|
||||
const aspect = item.width / item.height;
|
||||
const baseWidth = (aspect * ROW_HEIGHT) * scaleFactor;
|
||||
const actualWidth = baseWidth - (totalSpacing / itemEls.length);
|
||||
|
||||
itemEl.style.width = `${actualWidth}px`;
|
||||
itemEl.style.height = `${scaleFactor * ROW_HEIGHT}px`;
|
||||
itemEl.style.marginRight = `${ITEM_SPACING}px`;
|
||||
|
||||
row.appendChild(itemEl);
|
||||
}
|
||||
|
||||
container.appendChild(row);
|
||||
}
|
||||
|
||||
let rowItemEls = [];
|
||||
let rowWidth = 0;
|
||||
|
||||
for (const itemEl of itemElements) {
|
||||
const index = parseInt(itemEl.getAttribute('data-index'), 10);
|
||||
const item = showcaseItems[index];
|
||||
|
||||
const aspect = item.width / item.height;
|
||||
rowWidth += aspect * ROW_HEIGHT;
|
||||
|
||||
rowItemEls.push(itemEl);
|
||||
|
||||
if (rowWidth > width) {
|
||||
addRow(rowItemEls, rowWidth, showcaseContainer);
|
||||
|
||||
rowItemEls = [];
|
||||
rowWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
addRow(rowItemEls, rowWidth, showcaseContainer);
|
||||
}
|
||||
|
||||
function loadImages() {
|
||||
const items = showcaseContainer.querySelectorAll('.showcase-item');
|
||||
for (const item of items) {
|
||||
const i = parseInt(item.getAttribute('data-index'), 10);
|
||||
addThumbnailFuncs[i]();
|
||||
}
|
||||
}
|
||||
|
||||
layout();
|
||||
layout(); // scrollbars are fun!!
|
||||
|
||||
loadImages();
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
layout();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -238,6 +238,8 @@ func AtomFeed(c *RequestContext) ResponseData {
|
|||
INNER JOIN auth_user AS owner ON owner.id = snippet.owner_id
|
||||
LEFT JOIN handmade_asset AS asset ON asset.id = snippet.asset_id
|
||||
LEFT JOIN handmade_discordmessage AS discord_message ON discord_message.id = snippet.discord_message_id
|
||||
WHERE
|
||||
NOT snippet.is_jam
|
||||
ORDER BY snippet.when DESC
|
||||
LIMIT $1
|
||||
`,
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package website
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.handmade.network/hmn/hmn/src/db"
|
||||
"git.handmade.network/hmn/hmn/src/hmnurl"
|
||||
"git.handmade.network/hmn/hmn/src/models"
|
||||
"git.handmade.network/hmn/hmn/src/oops"
|
||||
"git.handmade.network/hmn/hmn/src/templates"
|
||||
)
|
||||
|
||||
|
@ -16,6 +20,45 @@ func JamIndex(c *RequestContext) ResponseData {
|
|||
daysUntil = 0
|
||||
}
|
||||
|
||||
c.Perf.StartBlock("SQL", "Fetch showcase snippets")
|
||||
type snippetQuery struct {
|
||||
Owner models.User `db:"owner"`
|
||||
Snippet models.Snippet `db:"snippet"`
|
||||
Asset *models.Asset `db:"asset"`
|
||||
DiscordMessage *models.DiscordMessage `db:"discord_message"`
|
||||
}
|
||||
snippetQueryResult, err := db.Query(c.Context(), c.Conn, snippetQuery{},
|
||||
`
|
||||
SELECT $columns
|
||||
FROM
|
||||
handmade_snippet AS snippet
|
||||
INNER JOIN auth_user AS owner ON owner.id = snippet.owner_id
|
||||
LEFT JOIN handmade_asset AS asset ON asset.id = snippet.asset_id
|
||||
LEFT JOIN handmade_discordmessage AS discord_message ON discord_message.id = snippet.discord_message_id
|
||||
WHERE
|
||||
snippet.is_jam
|
||||
ORDER BY snippet.when DESC
|
||||
LIMIT 20
|
||||
`,
|
||||
)
|
||||
if err != nil {
|
||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch jam snippets"))
|
||||
}
|
||||
snippetQuerySlice := snippetQueryResult.ToSlice()
|
||||
showcaseItems := make([]templates.TimelineItem, 0, len(snippetQuerySlice))
|
||||
for _, s := range snippetQuerySlice {
|
||||
row := s.(*snippetQuery)
|
||||
timelineItem := SnippetToTimelineItem(&row.Snippet, row.Asset, row.DiscordMessage, &row.Owner, c.Theme)
|
||||
if timelineItem.Type != templates.TimelineTypeSnippetYoutube {
|
||||
showcaseItems = append(showcaseItems, timelineItem)
|
||||
}
|
||||
}
|
||||
c.Perf.EndBlock()
|
||||
|
||||
c.Perf.StartBlock("SHOWCASE", "Convert to json")
|
||||
showcaseJson := templates.TimelineItemsToJSON(showcaseItems)
|
||||
c.Perf.EndBlock()
|
||||
|
||||
baseData := getBaseDataAutocrumb(c, "Wheel Reinvention Jam")
|
||||
baseData.OpenGraphItems = []templates.OpenGraphItem{
|
||||
{Property: "og:site_name", Value: "Handmade.Network"},
|
||||
|
@ -28,11 +71,13 @@ func JamIndex(c *RequestContext) ResponseData {
|
|||
type JamPageData struct {
|
||||
templates.BaseData
|
||||
DaysUntil int
|
||||
ShowcaseItemsJSON string
|
||||
}
|
||||
|
||||
res.MustWriteTemplate("wheeljam_index.html", JamPageData{
|
||||
BaseData: baseData,
|
||||
DaysUntil: daysUntil,
|
||||
ShowcaseItemsJSON: showcaseJson,
|
||||
}, c.Perf)
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -232,6 +232,8 @@ func Index(c *RequestContext) ResponseData {
|
|||
INNER JOIN auth_user AS owner ON owner.id = snippet.owner_id
|
||||
LEFT JOIN handmade_asset AS asset ON asset.id = snippet.asset_id
|
||||
LEFT JOIN handmade_discordmessage AS discord_message ON discord_message.id = snippet.discord_message_id
|
||||
WHERE
|
||||
NOT snippet.is_jam
|
||||
ORDER BY snippet.when DESC
|
||||
LIMIT 20
|
||||
`,
|
||||
|
|
|
@ -32,6 +32,8 @@ func Showcase(c *RequestContext) ResponseData {
|
|||
INNER JOIN auth_user AS owner ON owner.id = snippet.owner_id
|
||||
LEFT JOIN handmade_asset AS asset ON asset.id = snippet.asset_id
|
||||
LEFT JOIN handmade_discordmessage AS discord_message ON discord_message.id = snippet.discord_message_id
|
||||
WHERE
|
||||
NOT snippet.is_jam
|
||||
ORDER BY snippet.when DESC
|
||||
`,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue