Merge branch 'nuke-scss' of git.handmade.network:hmn/hmn into nuke-scss

This commit is contained in:
Asaf Gartner 2024-06-25 22:50:51 +03:00
commit 410c94bb51
37 changed files with 324 additions and 986 deletions

View File

@ -375,7 +375,7 @@ function editTimelineSnippet(timelineItemEl, stickyProjectId) {
let ownerAvatar = timelineItemEl.querySelector(".avatar")?.src;
let creationDate = new Date(timelineItemEl.querySelector("time").dateTime);
let rawDesc = timelineItemEl.querySelector(".rawdesc").textContent;
let attachment = timelineItemEl.querySelector(".timeline-content-box")?.children?.[0];
let attachment = timelineItemEl.querySelector(".timeline-media")?.children?.[0];
let projectIds = [];
let projectEls = timelineItemEl.querySelectorAll(".projects > a");
for (let i = 0; i < projectEls.length; ++i) {

View File

@ -1,106 +1,24 @@
function TabState(tabbed) {
this.container = tabbed;
this.tabs = tabbed.querySelector(".tab");
function initTabs(container, initialTab = null) {
const buttons = Array.from(container.querySelectorAll("[data-tab-button]"));
const tabs = Array.from(container.querySelectorAll("[data-tab]"));
this.tabbar = document.createElement("div");
this.tabbar.classList.add("tab-bar");
this.container.insertBefore(this.tabbar, this.container.firstChild);
this.current_i = -1;
this.tab_buttons = [];
}
function switch_tab_old(state, tab_i) {
return function() {
if (state.current_i >= 0) {
state.tabs[state.current_i].classList.add("hidden");
state.tab_buttons[state.current_i].classList.remove("current");
}
state.tabs[tab_i].classList.remove("hidden");
state.tab_buttons[tab_i].classList.add("current");
var hash = "";
if (state.tabs[tab_i].hasAttribute("data-url-hash")) {
hash = state.tabs[tab_i].getAttribute("data-url-hash");
}
window.location.hash = hash;
state.current_i = tab_i;
};
}
document.addEventListener("DOMContentLoaded", function() {
const tabContainers = document.getElementsByClassName("tabbed");
for (const container of tabContainers) {
const tabBar = document.createElement("div");
tabBar.classList.add("tab-bar");
container.insertAdjacentElement('afterbegin', tabBar);
const tabs = container.querySelectorAll(".tab");
for (let i = 0; i < tabs.length; i++) {
const tab = tabs[i];
tab.classList.toggle('dn', i > 0);
const slug = tab.getAttribute("data-slug");
// TODO: Should this element be a link?
const tabButton = document.createElement("div");
tabButton.classList.add("tab-button");
tabButton.classList.toggle("current", i === 0);
tabButton.innerText = tab.getAttribute("data-name");
tabButton.setAttribute("data-slug", slug);
tabButton.addEventListener("click", () => {
switchTab(container, slug);
});
tabBar.appendChild(tabButton);
}
const initialSlug = window.location.hash;
if (initialSlug) {
switchTab(container, initialSlug.substring(1));
}
}
});
function switchTab(container, slug) {
const tabs = container.querySelectorAll('.tab');
let didMatch = false;
for (const tab of tabs) {
const slugMatches = tab.getAttribute("data-slug") === slug;
tab.classList.toggle('dn', !slugMatches);
if (slugMatches) {
didMatch = true;
}
if (!initialTab) {
initialTab = tabs[0].getAttribute("data-tab");
}
const tabButtons = document.querySelectorAll(".tab-button");
for (const tabButton of tabButtons) {
const buttonSlug = tabButton.getAttribute("data-slug");
tabButton.classList.toggle('current', slug === buttonSlug);
function switchTo(name) {
for (const tab of tabs) {
tab.hidden = tab.getAttribute("data-tab") !== name;
}
for (const button of buttons) {
button.classList.toggle("tab-button-active", button.getAttribute("data-tab-button") === name);
}
}
switchTo(initialTab);
if (!didMatch) {
// switch to first tab as a fallback
tabs[0].classList.remove('dn');
tabButtons[0].classList.add('current');
for (const button of buttons) {
button.addEventListener("click", () => {
switchTo(button.getAttribute("data-tab-button"));
});
}
window.location.hash = slug;
}
function switchToTabOfElement(container, el) {
const tabs = Array.from(container.querySelectorAll('.tab'));
let target = el.parentElement;
while (target) {
if (tabs.includes(target)) {
switchTab(container, target.getAttribute("data-slug"));
return;
}
target = target.parentElement;
}
}

View File

@ -7159,9 +7159,6 @@ code {
--color: black;
--link-color: #d12991;
--red: #c61d24;
--dim-color: #333;
--dimmer-color: #999;
--dimmest-color: #bbb;
--theme-color: #b1b1b1;
--theme-color-dim: #c0c0c0;
--theme-color-dimmer: #dddddd;
@ -7173,6 +7170,7 @@ code {
--card-background: #ebebeb;
--card-background-hover: #f1f1f1;
--card-background-transparent: #ebebeb00;
--timeline-media-background: #b4b4b466;
--bg-1: #f8f8f8;
--bg-2: #e8e8e8;
--bg-3: #d8d8d8;
@ -7200,9 +7198,6 @@ code {
--color: #eee;
--link-color: #ff5dc2;
--color-error: #ff6666;
--dim-color: #bbb;
--dimmer-color: #999;
--dimmest-color: #777;
--theme-color: #666;
--theme-color-dim: #444;
--theme-color-dimmer: #383838;
@ -7214,6 +7209,7 @@ code {
--card-background: #494949;
--card-background-hover: #333;
--card-background-transparent: #24242400;
--timeline-media-background: #24242466;
--bg-1: #1f1f1f;
--bg-2: #2f2f2f;
--bg-3: #494949;
@ -7323,27 +7319,6 @@ pre,
flex-shrink: 1;
}
}
.b--dim {
border-color: var(--dim-color);
}
.b--dimmer {
border-color: var(--dimmer-color);
}
.b--dimmest {
border-color: var(--dimmest-color);
}
.b--theme {
border-color: var(--theme-color);
}
.b--theme-dim {
border-color: var(--theme-color-dim);
}
.b--theme-dimmer {
border-color: var(--theme-color-dimmer);
}
.b--theme-dimmest {
border-color: var(--theme-color-dimmest);
}
.b--theme-dark {
border-color: var(--theme-color-dark);
}
@ -7393,24 +7368,6 @@ pre,
.c--inherit:active {
color: inherit;
}
.c--dim {
color: var(--dim-color);
}
.c--theme-dim {
color: var(--theme-color-dim);
}
.c--dimmer {
color: var(--dimmer-color);
}
.c--theme-dimmer {
color: var(--theme-color-dimmer);
}
.c--dimmest {
color: var(--dimmest-color);
}
.c--theme-dimmest {
color: var(--theme-color-dimmest);
}
.f8 {
font-size: 0.65rem;
}
@ -7809,7 +7766,7 @@ pre,
align-items: center;
border-style: dashed;
border-width: 0 0 1px;
border-color: var(--dimmest-color);
border-color: var(--bg-3);
}
@media screen and (min-width: 35em) {
.optionbar {
@ -7885,7 +7842,7 @@ pre,
transition: all 100ms ease-in-out;
}
.carousel-container .carousel-button:hover {
background-color: var(--dimmest-color);
background-color: var(--bg-3);
}
.carousel-container .carousel-button.active {
border-color: var(--theme-color);
@ -7967,10 +7924,10 @@ pre,
.post-content th,
.post-content td {
padding: var(--spacing-extra-small) var(--spacing-small);
border: 1px solid var(--dimmest-color);
border: 1px solid var(--border-color);
}
.post-content code {
background-color: var(--dim-background);
background-color: var(--bg-3);
padding: .2em 0;
white-space: nowrap;
}
@ -7982,12 +7939,12 @@ pre,
}
.post-content pre > code,
.post-content pre.hmn-code {
background-color: var(--dim-background);
background-color: var(--bg-3);
padding: 0.7em;
overflow-x: auto;
}
.post-content blockquote {
border-color: var(--dimmest-color);
border-color: var(--bg-3);
margin-left: var(--spacing-small);
padding-left: var(--spacing-small);
margin-right: 0;
@ -8130,7 +8087,7 @@ pre,
height: var(--height);
border-width: 0 0 1px 1px;
border-style: solid;
border-color: var(--dimmest-color);
border-color: var(--bg-3);
left: -1.5rem;
top: calc(1rem - var(--height));
border-bottom-left-radius: 0.5rem;
@ -8471,7 +8428,7 @@ header.old .submenu > a {
}
}
header {
background-color: var(--bg-3);
background-color: var(--bg-2);
border-bottom-style: solid;
border-bottom-width: 1px;
}
@ -8501,7 +8458,7 @@ header .header-nav .submenu {
position: absolute;
z-index: 100;
min-width: 8rem;
background-color: var(--card-background);
background-color: var(--bg-2);
border-style: solid;
border-width: 1px;
border-top-width: 0;
@ -8887,11 +8844,20 @@ code .ss,
color: #a31515;
}
/* src/rawdata/scss/tabs.css */
.tab-button {
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.tab-button-active {
border-color: var(--link-color);
}
/* src/rawdata/scss/timeline.css */
.avatar {
object-fit: cover;
overflow: hidden;
background-color: var(--dimmest-color);
background-color: var(--bg-3);
flex-shrink: 0;
border: none;
width: var(--avatar-size-normal);
@ -8909,16 +8875,28 @@ code .ss,
--fade-color: var(--card-background);
color: var(--main-color);
}
.timeline-item .timeline-content-box.timeline-item-bg {
background-color: var(--timeline-content-background);
.timeline-item .timeline-media {
background-color: var(--timeline-media-background);
max-height: 60vh;
}
.timeline-item .timeline-content-box > * {
.timeline-item .timeline-media.timeline-embed {
height: 0;
position: relative;
padding-bottom: 56.25%;
}
.timeline-item .timeline-media.timeline-embed > iframe {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
}
.timeline-item .timeline-media > * {
display: block;
max-width: 100%;
max-height: 80vh;
}
.timeline-item .avatar {
width: 2.5rem;
}
.timeline-modal .container {
max-height: 100vh;

View File

@ -1,309 +0,0 @@
/*
Inserts a CSS expression with one or more custom variables.
You can provide an arbitrary number of strings in the second
argument, separated by spaces. Any strings corresponding to
variable names will be replaced by the correct values, while
other strings are left untouched.
Example usage:
@include usevar(border-color, dimmer-color);
@include usevar(background, "linear-gradient(" dim-background-transparent "," dim-background ")");
For clarity and to avoid syntax issues, you are encouraged to
use unquoted strings for variables and quoted strings for
everything else.
For convenience in common cases, if only a single argument
is provided and it does not match an existing variable, this
will throw an error.
*/
pre, code, .codeblock {
/* Comment */
/* Error */
/* Keyword */
/* Literal */
/* Name */
/* Operator */
/* Punctuation */
/* Comment.Multiline */
/* Comment.Preproc */
/* Comment.Single */
/* Comment.Special */
/* Generic.Emph */
/* Generic.Strong */
/* Keyword.Constant */
/* Keyword.Declaration */
/* Keyword.Namespace */
/* Keyword.Pseudo */
/* Keyword.Reserved */
/* Keyword.Type */
/* Literal.Date */
/* Literal.Number */
/* Literal.String */
/* Name.Attribute */
/* Name.Builtin */
/* Name.Class */
/* Name.Constant */
/* Name.Decorator */
/* Name.Entity */
/* Name.Exception */
/* Name.Function */
/* Name.Label */
/* Name.Namespace */
/* Name.Other */
/* Name.Property */
/* Name.Tag */
/* Name.Variable */
/* Operator.Word */
/* Text.Whitespace */
/* Literal.Number.Float */
/* Literal.Number.Hex */
/* Literal.Number.Integer */
/* Literal.Number.Oct */
/* Literal.String.Backtick */
/* Literal.String.Char */
/* Literal.String.Doc */
/* Literal.String.Double */
/* Literal.String.Escape */
/* Literal.String.Heredoc */
/* Literal.String.Interpol */
/* Literal.String.Other */
/* Literal.String.Regex */
/* Literal.String.Single */
/* Literal.String.Symbol */
/* Name.Builtin.Pseudo */
/* Name.Variable.Class */
/* Name.Variable.Global */
/* Name.Variable.Instance */
/* Literal.Number.Integer.Long */
/* Generic Heading & Diff Header */
/* Generic.Subheading & Diff Unified/Comment? */
/* Generic.Deleted & Diff Deleted */
/* Generic.Inserted & Diff Inserted */ }
pre .hll, code .hll, .codeblock .hll {
background-color: #49483e; }
pre .c, code .c, .codeblock .c {
color: #75715e; }
pre .err, code .err, .codeblock .err {
color: #ff0000; }
pre .k, code .k, .codeblock .k {
color: #66d9ef; }
pre .l, code .l, .codeblock .l {
color: #ae81ff; }
pre .n, code .n, .codeblock .n {
color: #f8f8f2; }
pre .o, code .o, .codeblock .o {
color: #f92672; }
pre .p, code .p, .codeblock .p {
color: #f8f8f2; }
pre .cm, code .cm, .codeblock .cm {
color: #75715e; }
pre .cp, code .cp, .codeblock .cp {
color: #75715e; }
pre .c1, code .c1, .codeblock .c1 {
color: #75715e; }
pre .cs, code .cs, .codeblock .cs {
color: #75715e; }
pre .ge, code .ge, .codeblock .ge {
font-style: italic; }
pre .gs, code .gs, .codeblock .gs {
font-weight: bold; }
pre .kc, code .kc, .codeblock .kc {
color: #66d9ef; }
pre .kd, code .kd, .codeblock .kd {
color: #66d9ef; }
pre .kn, code .kn, .codeblock .kn {
color: #f92672; }
pre .kp, code .kp, .codeblock .kp {
color: #66d9ef; }
pre .kr, code .kr, .codeblock .kr {
color: #66d9ef; }
pre .kt, code .kt, .codeblock .kt {
color: #66d9ef; }
pre .ld, code .ld, .codeblock .ld {
color: #e6db74; }
pre .m, code .m, .codeblock .m {
color: #ae81ff; }
pre .s, code .s, .codeblock .s {
color: #e6db74; }
pre .na, code .na, .codeblock .na {
color: #a6e22e; }
pre .nb, code .nb, .codeblock .nb {
color: #f8f8f2; }
pre .nc, code .nc, .codeblock .nc {
color: #a6e22e; }
pre .no, code .no, .codeblock .no {
color: #66d9ef; }
pre .nd, code .nd, .codeblock .nd {
color: #a6e22e; }
pre .ni, code .ni, .codeblock .ni {
color: #f8f8f2; }
pre .ne, code .ne, .codeblock .ne {
color: #a6e22e; }
pre .nf, code .nf, .codeblock .nf {
color: #a6e22e; }
pre .nl, code .nl, .codeblock .nl {
color: #f8f8f2; }
pre .nn, code .nn, .codeblock .nn {
color: #f8f8f2; }
pre .nx, code .nx, .codeblock .nx {
color: #a6e22e; }
pre .py, code .py, .codeblock .py {
color: #f8f8f2; }
pre .nt, code .nt, .codeblock .nt {
color: #f92672; }
pre .nv, code .nv, .codeblock .nv {
color: #f8f8f2; }
pre .ow, code .ow, .codeblock .ow {
color: #f92672; }
pre .w, code .w, .codeblock .w {
color: #f8f8f2; }
pre .mf, code .mf, .codeblock .mf {
color: #ae81ff; }
pre .mh, code .mh, .codeblock .mh {
color: #ae81ff; }
pre .mi, code .mi, .codeblock .mi {
color: #ae81ff; }
pre .mo, code .mo, .codeblock .mo {
color: #ae81ff; }
pre .sb, code .sb, .codeblock .sb {
color: #e6db74; }
pre .sc, code .sc, .codeblock .sc {
color: #e6db74; }
pre .sd, code .sd, .codeblock .sd {
color: #e6db74; }
pre .s2, code .s2, .codeblock .s2 {
color: #e6db74; }
pre .se, code .se, .codeblock .se {
color: #ae81ff; }
pre .sh, code .sh, .codeblock .sh {
color: #e6db74; }
pre .si, code .si, .codeblock .si {
color: #e6db74; }
pre .sx, code .sx, .codeblock .sx {
color: #e6db74; }
pre .sr, code .sr, .codeblock .sr {
color: #e6db74; }
pre .s1, code .s1, .codeblock .s1 {
color: #e6db74; }
pre .ss, code .ss, .codeblock .ss {
color: #e6db74; }
pre .bp, code .bp, .codeblock .bp {
color: #f8f8f2; }
pre .vc, code .vc, .codeblock .vc {
color: #f8f8f2; }
pre .vg, code .vg, .codeblock .vg {
color: #f8f8f2; }
pre .vi, code .vi, .codeblock .vi {
color: #f8f8f2; }
pre .il, code .il, .codeblock .il {
color: #ae81ff; }
pre .gu, code .gu, .codeblock .gu {
color: #75715e; }
pre .gd, code .gd, .codeblock .gd {
color: #f92672; }
pre .gi, code .gi, .codeblock .gi {
color: #a6e22e; }
.light {
background-color: #fff;
color: #000; }
:root {
--fg-font-color: #eee;
--theme-color: #666;
--theme-color-dim: #444;
--theme-color-dimmer: #383838;
--theme-color-dimmest: #333;
--theme-color-dark: #666;
--theme-color-light: #666;
--link-color: #aaa;
--link-border-color: #aaa;
--hr-color: #aaa;
--main-background-color: #202020;
--main-color: #eee;
--dim-color: #bbb;
--dimmer-color: #999;
--dimmest-color: #777;
--menu-bottom-border-color: #444;
--login-popup-background: #181818;
--content-background: #202020;
--content-background-transparent: rgba(32, 32, 32, 0);
--dim-background: #252525;
--dim-background-transparent: rgba(37, 37, 37, 0);
--text-background: #181818;
--spoiler-border: #777;
--background-even-background: #242424;
--project-card-border-color: #333;
--project-user-suggestions-background: #222;
--project-user-suggestions-border-color: #444;
--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;
--notice-warn-color: #876327;
--notice-failure-color: #7a2020;
--optionbar-border-color: #333;
--tab-background: #181818;
--tab-border-color: #3f3f3f;
--tab-button-background: #303030;
--tab-button-background-hover: #383838;
--tab-button-background-current: #181818;
--form-check-background: #252527;
--form-check-border-color: #666;
--form-check-border-color-hover: #084068;
--form-text-background: #181818;
--form-text-background-active: #252527;
--form-text-border-color: #444;
--form-text-border-color-active: #084068;
--form-button-color: #999;
--form-button-color-active: #4c9ed9;
--form-button-background: #383838;
--form-button-background-active: #303840;
--form-button-border-color: transparent;
--form-button-inline-border-color: transparent;
--form-error-color: #c61d24;
--landing-search-background: #282828;
--landing-search-background-hover: #181818;
--editor-toolbar-background: #282828;
--editor-toolbar-border-color: #333;
--editor-toolbar-button-background: #282828;
--editor-toolbar-button-background-hover: #333;
--editor-toolbar-button-border-color: #333;
--post-blockquote-border-color: #555;
--forum-even-background: #242424;
--forum-thread-read-color: #777;
--forum-thread-read-link-color: #999;
--forum-post-author-color: #999;
--forum-diff-source-background: #181818;
--forum-diff-source-border-color: #444;
--forum-diff-replace-background: #18283a;
--forum-diff-replace-border-color: #223d5b;
--forum-diff-delete-background: #3a1818;
--forum-diff-delete-border-color: #6b1e1c;
--forum-diff-insert-background: #233a18;
--forum-diff-insert-border-color: #30591b;
--card-background: #282828;
--card-background-hover: #333;
--timeline-content-background: rgba(255, 255, 255, 0.06);
--irc-border-color: #333;
--irc-tab-current-shadow: 0px 0px 5px #000 inset;
--irc-tab-close-button-color: #bbb;
--irc-tab-close-button-background: #444;
--irc-nick-border-color: #444;
--irc-users-color: #aaa;
--irc-users-background: #181818;
--irc-users-border-color: transparent;
--irc-users-popout-background: #181818;
--irc-users-popout-border-color-left: #444;
--irc-users-popout-border-color-right: #333;
--code-line-number-color: #444;
--library-star-btn-background: #252525;
--library-star-btn-border-color: #bbb;
--library-star-btn-a-border-color: #999;
--library-star-btn-a-hover-background: #333; }

View File

@ -1,327 +0,0 @@
/*
Inserts a CSS expression with one or more custom variables.
You can provide an arbitrary number of strings in the second
argument, separated by spaces. Any strings corresponding to
variable names will be replaced by the correct values, while
other strings are left untouched.
Example usage:
@include usevar(border-color, dimmer-color);
@include usevar(background, "linear-gradient(" dim-background-transparent "," dim-background ")");
For clarity and to avoid syntax issues, you are encouraged to
use unquoted strings for variables and quoted strings for
everything else.
For convenience in common cases, if only a single argument
is provided and it does not match an existing variable, this
will throw an error.
*/
pre, code, .codeblock {
/* Comment */
/* Error */
/* Keyword */
/* Operator */
/* Comment.Multiline */
/* Comment.Preproc */
/* Comment.Single */
/* Comment.Special */
/* Generic.Deleted */
/* Generic.Emph */
/* Generic.Error */
/* Generic.Heading */
/* Generic.Inserted */
/* Generic.Output */
/* Generic.Prompt */
/* Generic.Strong */
/* Generic.Subheading */
/* Generic.Traceback */
/* Keyword.Constant */
/* Keyword.Declaration */
/* Keyword.Namespace */
/* Keyword.Pseudo */
/* Keyword.Reserved */
/* Keyword.Type */
/* Literal.Number */
/* Literal.String */
/* Name.Attribute */
/* Name.Builtin */
/* Name.Class */
/* Name.Constant */
/* Name.Decorator */
/* Name.Entity */
/* Name.Exception */
/* Name.Function */
/* Name.Label */
/* Name.Namespace */
/* Name.Tag */
/* Name.Variable */
/* Operator.Word */
/* Text.Whitespace */
/* Literal.Number.Float */
/* Literal.Number.Hex */
/* Literal.Number.Integer */
/* Literal.Number.Oct */
/* Literal.String.Backtick */
/* Literal.String.Char */
/* Literal.String.Doc */
/* Literal.String.Double */
/* Literal.String.Escape */
/* Literal.String.Heredoc */
/* Literal.String.Interpol */
/* Literal.String.Other */
/* Literal.String.Regex */
/* Literal.String.Single */
/* Literal.String.Symbol */
/* Name.Builtin.Pseudo */
/* Name.Variable.Class */
/* Name.Variable.Global */
/* Name.Variable.Instance */
/* Literal.Number.Integer.Long */ }
pre .hll, code .hll, .codeblock .hll {
background-color: #ffffcc; }
pre .c, code .c, .codeblock .c {
color: #60a0b0;
font-style: italic; }
pre .err, code .err, .codeblock .err {
color: #FF0000; }
pre .k, code .k, .codeblock .k {
color: #007020;
font-weight: bold; }
pre .o, code .o, .codeblock .o {
color: #666666; }
pre .cm, code .cm, .codeblock .cm {
color: #60a0b0;
font-style: italic; }
pre .cp, code .cp, .codeblock .cp {
color: #007020; }
pre .c1, code .c1, .codeblock .c1 {
color: #60a0b0;
font-style: italic; }
pre .cs, code .cs, .codeblock .cs {
color: #60a0b0;
background-color: #fff0f0; }
pre .gd, code .gd, .codeblock .gd {
color: #A00000; }
pre .ge, code .ge, .codeblock .ge {
font-style: italic; }
pre .gr, code .gr, .codeblock .gr {
color: #FF0000; }
pre .gh, code .gh, .codeblock .gh {
color: #000080;
font-weight: bold; }
pre .gi, code .gi, .codeblock .gi {
color: #00A000; }
pre .go, code .go, .codeblock .go {
color: #808080; }
pre .gp, code .gp, .codeblock .gp {
color: #c65d09;
font-weight: bold; }
pre .gs, code .gs, .codeblock .gs {
font-weight: bold; }
pre .gu, code .gu, .codeblock .gu {
color: #800080;
font-weight: bold; }
pre .gt, code .gt, .codeblock .gt {
color: #0040D0; }
pre .kc, code .kc, .codeblock .kc {
color: #007020;
font-weight: bold; }
pre .kd, code .kd, .codeblock .kd {
color: #007020;
font-weight: bold; }
pre .kn, code .kn, .codeblock .kn {
color: #007020;
font-weight: bold; }
pre .kp, code .kp, .codeblock .kp {
color: #007020; }
pre .kr, code .kr, .codeblock .kr {
color: #007020;
font-weight: bold; }
pre .kt, code .kt, .codeblock .kt {
color: #902000; }
pre .m, code .m, .codeblock .m {
color: #40a070; }
pre .s, code .s, .codeblock .s {
color: #4070a0; }
pre .na, code .na, .codeblock .na {
color: #4070a0; }
pre .nb, code .nb, .codeblock .nb {
color: #007020; }
pre .nc, code .nc, .codeblock .nc {
color: #0e84b5;
font-weight: bold; }
pre .no, code .no, .codeblock .no {
color: #60add5; }
pre .nd, code .nd, .codeblock .nd {
color: #555555;
font-weight: bold; }
pre .ni, code .ni, .codeblock .ni {
color: #d55537;
font-weight: bold; }
pre .ne, code .ne, .codeblock .ne {
color: #007020; }
pre .nf, code .nf, .codeblock .nf {
color: #06287e; }
pre .nl, code .nl, .codeblock .nl {
color: #002070;
font-weight: bold; }
pre .nn, code .nn, .codeblock .nn {
color: #0e84b5;
font-weight: bold; }
pre .nt, code .nt, .codeblock .nt {
color: #062873;
font-weight: bold; }
pre .nv, code .nv, .codeblock .nv {
color: #bb60d5; }
pre .ow, code .ow, .codeblock .ow {
color: #007020;
font-weight: bold; }
pre .w, code .w, .codeblock .w {
color: #bbbbbb; }
pre .mf, code .mf, .codeblock .mf {
color: #40a070; }
pre .mh, code .mh, .codeblock .mh {
color: #40a070; }
pre .mi, code .mi, .codeblock .mi {
color: #40a070; }
pre .mo, code .mo, .codeblock .mo {
color: #40a070; }
pre .sb, code .sb, .codeblock .sb {
color: #4070a0; }
pre .sc, code .sc, .codeblock .sc {
color: #4070a0; }
pre .sd, code .sd, .codeblock .sd {
color: #4070a0;
font-style: italic; }
pre .s2, code .s2, .codeblock .s2 {
color: #4070a0; }
pre .se, code .se, .codeblock .se {
color: #4070a0;
font-weight: bold; }
pre .sh, code .sh, .codeblock .sh {
color: #4070a0; }
pre .si, code .si, .codeblock .si {
color: #70a0d0;
font-style: italic; }
pre .sx, code .sx, .codeblock .sx {
color: #c65d09; }
pre .sr, code .sr, .codeblock .sr {
color: #235388; }
pre .s1, code .s1, .codeblock .s1 {
color: #4070a0; }
pre .ss, code .ss, .codeblock .ss {
color: #517918; }
pre .bp, code .bp, .codeblock .bp {
color: #007020; }
pre .vc, code .vc, .codeblock .vc {
color: #bb60d5; }
pre .vg, code .vg, .codeblock .vg {
color: #bb60d5; }
pre .vi, code .vi, .codeblock .vi {
color: #bb60d5; }
pre .il, code .il, .codeblock .il {
color: #40a070; }
.dark {
background-color: #222;
color: #bbb; }
:root {
--fg-font-color: black;
--theme-color: #666;
--theme-color-dim: #aaa;
--theme-color-dimmer: #bbb;
--theme-color-dimmest: #ccc;
--theme-color-dark: #666;
--theme-color-light: #666;
--link-color: #666;
--link-border-color: #666;
--hr-color: #444;
--main-background-color: #fff;
--main-color: black;
--dim-color: #333;
--dimmer-color: #999;
--dimmest-color: #bbb;
--menu-bottom-border-color: black;
--login-popup-background: #fbfbfb;
--content-background: #f8f8f8;
--content-background-transparent: rgba(248, 248, 248, 0);
--dim-background: #f0f0f0;
--dim-background-transparent: rgba(240, 240, 240, 0);
--text-background: #f9f9f9;
--spoiler-border: #aaa;
--background-even-background: #f8f8f8;
--project-card-border-color: #aaa;
--project-user-suggestions-background: #fff;
--project-user-suggestions-border-color: #ddd;
--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;
--notice-warn-color: #aa7d30;
--notice-failure-color: #b42222;
--optionbar-border-color: #ccc;
--tab-background: #fff;
--tab-border-color: #d8d8d8;
--tab-button-background: #dfdfdf;
--tab-button-background-hover: #efefef;
--tab-button-background-current: #fff;
--form-check-background: #fafafc;
--form-check-border-color: #999;
--form-check-border-color-hover: #4c9ed9;
--form-text-background: #fff;
--form-text-background-active: #fafafc;
--form-text-border-color: #999;
--form-text-border-color-active: #4c9ed9;
--form-button-color: black;
--form-button-color-active: #4c9ed9;
--form-button-background: #fff;
--form-button-background-active: #f2f2f2;
--form-button-border-color: #ccc;
--form-button-inline-border-color: #999;
--form-error-color: #c61d24;
--landing-search-background: #f8f8f8;
--landing-search-background-hover: #fefeff;
--editor-toolbar-background: #fff;
--editor-toolbar-border-color: transparent;
--editor-toolbar-button-background: transparent;
--editor-toolbar-button-background-hover: #ddd;
--editor-toolbar-button-border-color: #ccc;
--post-blockquote-border-color: #ddd;
--forum-even-background: #f0f0f0;
--forum-thread-read-color: #555;
--forum-thread-read-link-color: #888;
--forum-post-author-color: #333;
--forum-diff-source-background: #fff;
--forum-diff-source-border-color: #999;
--forum-diff-replace-background: #adcef4;
--forum-diff-replace-border-color: #4787d1;
--forum-diff-delete-background: #e57979;
--forum-diff-delete-border-color: #c12626;
--forum-diff-insert-background: #96e579;
--forum-diff-insert-border-color: #5baa3f;
--card-background: #e8e8e8;
--card-background-hover: #f0f0f0;
--timeline-content-background: rgba(0, 0, 0, 0.2);
--irc-border-color: #ddd;
--irc-tab-current-shadow: 0px 0px 5px #bbb inset;
--irc-tab-close-button-color: #fff;
--irc-tab-close-button-background: #aaa;
--irc-nick-border-color: #ccc;
--irc-users-color: black;
--irc-users-background: #fff;
--irc-users-border-color: #ccc;
--irc-users-popout-background: #fff;
--irc-users-popout-border-color-left: #bbb;
--irc-users-popout-border-color-right: #ccc;
--code-line-number-color: #777;
--library-star-btn-background: #fff;
--library-star-btn-border-color: #999;
--library-star-btn-a-border-color: #aaa;
--library-star-btn-a-hover-background: #fafafa; }

View File

@ -23,6 +23,7 @@ type ProjectsQuery struct {
// are generally visible to all users.
Lifecycles []models.ProjectLifecycle // If empty, defaults to visible lifecycles. Do not conflate this with permissions; those are checked separately.
Types ProjectTypeQuery // bitfield
FeaturedOnly bool
IncludeHidden bool
// Ignored when using FetchProject
@ -133,6 +134,9 @@ func FetchProjects(
}
qb.Add(`)`)
}
if q.FeaturedOnly {
qb.Add(`AND project.featured`)
}
if !q.IncludeHidden {
qb.Add(`AND NOT project.hidden`)
}

View File

@ -16,6 +16,8 @@ type SnippetQuery struct {
Tags []int
DiscordMessageIDs []string
FeaturedOnly bool
Limit, Offset int // if empty, no pagination
}

View File

@ -20,7 +20,7 @@
transition: all 100ms ease-in-out;
&:hover {
background-color: var(--dimmest-color);
background-color: var(--bg-3);
}
&.active {

View File

@ -87,11 +87,11 @@
th,
td {
padding: var(--spacing-extra-small) var(--spacing-small);
border: 1px solid var(--dimmest-color);
border: 1px solid var(--border-color);
}
code {
background-color: var(--dim-background);
background-color: var(--bg-3);
padding: .2em 0;
white-space: nowrap;
@ -106,14 +106,14 @@
pre>code,
pre.hmn-code {
background-color: var(--dim-background);
background-color: var(--bg-3);
padding: 0.7em;
overflow-x: auto;
}
blockquote {
border-color: var(--dimmest-color);
border-color: var(--bg-3);
margin-left: var(--spacing-small);
padding-left: var(--spacing-small);
margin-right: 0;

View File

@ -108,34 +108,6 @@ pre,
}
}
.b--dim {
border-color: var(--dim-color);
}
.b--dimmer {
border-color: var(--dimmer-color);
}
.b--dimmest {
border-color: var(--dimmest-color);
}
.b--theme {
border-color: var(--theme-color);
}
.b--theme-dim {
border-color: var(--theme-color-dim);
}
.b--theme-dimmer {
border-color: var(--theme-color-dimmer);
}
.b--theme-dimmest {
border-color: var(--theme-color-dimmest);
}
.b--theme-dark {
border-color: var(--theme-color-dark);
}
@ -201,30 +173,6 @@ pre,
}
}
.c--dim {
color: var(--dim-color);
}
.c--theme-dim {
color: var(--theme-color-dim);
}
.c--dimmer {
color: var(--dimmer-color);
}
.c--theme-dimmer {
color: var(--theme-color-dimmer);
}
.c--dimmest {
color: var(--dimmest-color);
}
.c--theme-dimmest {
color: var(--theme-color-dimmest);
}
.f8 {
font-size: 0.65rem;
}
@ -755,7 +703,7 @@ lite variant instead.
align-items: center;
border-style: dashed;
border-width: 0 0 1px;
border-color: var(--dimmest-color);
border-color: var(--bg-3);
@media screen and (min-width: 35em) {
flex-direction: row;

View File

@ -18,7 +18,7 @@
height: var(--height);
border-width: 0 0 1px 1px;
border-style: solid;
border-color: var(--dimmest-color);
border-color: var(--bg-3);
left: -1.5rem;
top: calc(1rem - var(--height));
border-bottom-left-radius: 0.5rem;

View File

@ -114,7 +114,7 @@ header.old {
}
header {
background-color: var(--bg-3);
background-color: var(--bg-2);
border-bottom-style: solid;
border-bottom-width: 1px;
@ -151,7 +151,7 @@ header {
position: absolute;
z-index: 100;
min-width: 8rem;
background-color: var(--card-background);
background-color: var(--bg-2);
border-style: solid;
border-width: 1px;
border-top-width: 0;

View File

@ -16,4 +16,5 @@
@import "projects.css";
@import "showcase.css";
@import "syntax.css";
@import "tabs.css";
@import "timeline.css";

View File

@ -0,0 +1,8 @@
.tab-button {
border-bottom: 2px solid transparent;
margin-bottom: -1px;
}
.tab-button-active {
border-color: var(--link-color);
}

View File

@ -1,7 +1,7 @@
.avatar {
object-fit: cover;
overflow: hidden;
background-color: var(--dimmest-color);
background-color: var(--bg-3);
flex-shrink: 0;
border: none;
@ -23,22 +23,34 @@
--fade-color: var(--card-background);
color: var(--main-color);
.timeline-content-box {
&.timeline-item-bg {
background-color: var(--timeline-content-background);
.timeline-media {
background-color: var(--timeline-media-background);
max-height: 60vh;
&.timeline-embed {
/* aspect-ratio aspect-ratio--16x9 */
height: 0;
position: relative;
padding-bottom: 56.25%;
>iframe {
/* aspect-ratio--object */
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
}
}
>* {
display: block;
max-width: 100%;
max-height: 80vh;
}
}
.avatar {
/* 40px */
width: 2.5rem;
}
}
.timeline-modal {

View File

@ -14,10 +14,6 @@ $breakpoint-large: screen and (min-width: 60em)
--link-color: #d12991;
--red: #c61d24;
--dim-color: #333;
--dimmer-color: #999;
--dimmest-color: #bbb;
/* Default theme colors in case the project.css is busted */
--theme-color: #b1b1b1;
--theme-color-dim: #c0c0c0;
@ -34,6 +30,8 @@ $breakpoint-large: screen and (min-width: 60em)
--card-background-hover: #f1f1f1;
--card-background-transparent: #ebebeb00;
--timeline-media-background: #b4b4b466;
--bg-1: #f8f8f8;
--bg-2: #e8e8e8;
--bg-3: #d8d8d8;
@ -71,10 +69,6 @@ $breakpoint-large: screen and (min-width: 60em)
--link-color: #ff5dc2;
--color-error: #ff6666;
--dim-color: #bbb;
--dimmer-color: #999;
--dimmest-color: #777;
--theme-color: #666;
--theme-color-dim: #444;
--theme-color-dimmer: #383838;
@ -91,6 +85,8 @@ $breakpoint-large: screen and (min-width: 60em)
--card-background-hover: #333;
--card-background-transparent: #24242400;
--timeline-media-background: #24242466;
--bg-1: #1f1f1f;
--bg-2: #2f2f2f;
--bg-3: #494949;

View File

@ -389,16 +389,17 @@ func TimelineItemsToJSON(items []TimelineItem) string {
builder.WriteString(item.Url)
builder.WriteString(`",`)
// TODO(redesign): This only serializes a single piece of media.
var mediaType TimelineItemMediaType
var assetUrl string
var thumbnailUrl string
var width, height int
if len(item.EmbedMedia) > 0 {
mediaType = item.EmbedMedia[0].Type
assetUrl = item.EmbedMedia[0].AssetUrl
thumbnailUrl = item.EmbedMedia[0].ThumbnailUrl
width = item.EmbedMedia[0].Width
height = item.EmbedMedia[0].Height
if len(item.Media) > 0 {
mediaType = item.Media[0].Type
assetUrl = item.Media[0].AssetUrl
thumbnailUrl = item.Media[0].ThumbnailUrl
width = item.Media[0].Width
height = item.Media[0].Height
}
builder.WriteString(`"media_type":`)

View File

@ -59,7 +59,7 @@
{{ cleancontrolchars .Description }}
]]>
</div>
{{ range .EmbedMedia }}
{{ range .Media }}
<div>
{{ if eq .Type mediaimage }}
<img src="{{ .AssetUrl }}"/>

View File

@ -1,4 +1,4 @@
<div class="breadcrumbs f7 o-80">
<div class="breadcrumbs f7">
{{ range $i, $breadcrumb := . }}
{{ if gt $i 0 }} » {{ end }}
<a href="{{ $breadcrumb.Url }}">{{ $breadcrumb.Name }}</a>

View File

@ -16,7 +16,7 @@
<div>{{ trim .Description }}</div>
</div>
</div>
{{ range .EmbedMedia }}
{{ range .Media }}
<div class="flex flex-column {{ if eq .Type mediaembed }}wide-screen{{ end }} justify-stretch iframe-fill">
{{ if eq .Type mediaimage }}
<img src="{{ .AssetUrl }}">

View File

@ -1,43 +1,64 @@
<div class="timeline-item flex flex-column pa3" data-id="{{ .ID }}" {{ with .FilterTitle }}data-filter-title="{{ . }}"{{ end }}>
{{/* top bar - avatar, info, date */}}
<div class="flex items-center">
{{ if .OwnerAvatarUrl }}
<a class="flex flex-shrink-0" href="{{ .OwnerUrl }}">
<img class="avatar avatar-user {{ if .SmallInfo }}avatar-small mr2{{ else }}mr3{{ end }}" src="{{ .OwnerAvatarUrl }}" />
<img class="avatar avatar-user {{ if .ForumLayout }}mr3{{ else }}mr2{{ end }}" src="{{ .OwnerAvatarUrl }}" />
</a>
{{ end }}
{{ if .ForumLayout }}
<div class="overflow-hidden flex-grow-1 flex flex-column g1 justify-center">
{{ with .Breadcrumbs }}
{{ template "breadcrumbs.html" . }}
{{ end }}
{{ if .Title }}
<div class="f5 lh-title {{ if not .AllowTitleWrap }}nowrap truncate{{ end }}">
{{ with .TypeTitle }}<b class="dn di-ns">{{ . }}:</b>{{ end }}
<a href="{{ .Url }}">{{ .Title }}</a>
</div>
{{ end }}
<div class="details link--normal">
<a class="user" href="{{ .OwnerUrl }}">{{ .OwnerName }}</a>
&mdash; {{ timehtml (absoluteshortdate .Date) .Date }}
</div>
</div>
<div class="overflow-hidden flex-grow-1 flex flex-column justify-center">
{{ if .Breadcrumbs }}
{{ template "breadcrumbs.html" .Breadcrumbs }}
{{ if .Editable }}
<a href="javascript:;" class="edit ml2">&#9998;</a>
<div class="dn rawdesc">{{ .RawDescription }}</div>
{{ end }}
{{ if .Title }}
<div class="f5 {{ if not .AllowTitleWrap }}nowrap truncate{{ end }}">
{{ with .TypeTitle }}<b class="dn di-ns">{{ . }}:</b>{{ end }}
<a href="{{ .Url }}">{{ .Title }}</a>
{{ else }}
<div class="overflow-hidden flex-grow-1 flex flex-column g1 justify-center link--normal">
{{ if .Breadcrumbs }}
<div>Use .ForumLayout if you want breadcrumbs :)</div>
{{ end }}
{{ if .Title }}
<div>Use .ForumLayout if you want a title :)</div>
{{ end }}
<a class="user b" href="{{ .OwnerUrl }}">{{ .OwnerName }}</a>
<a class="f6" href="{{ .Url }}">{{ timehtml (absoluteshortdate .Date) .Date }}</a>
</div>
{{ if eq (len .Projects) 1 }}
{{ $p := index .Projects 0 }}
<div class="overflow-hidden flex flex-column g1 justify-center link--normal tr">
<a class="user b" href="{{ $p.Url }}">{{ $p.Name }}</a>
</div>
{{ end }}
<div class="details">
<a class="user" href="{{ .OwnerUrl }}">{{ .OwnerName }}</a>
{{ if not .SmallInfo }}
&mdash; {{ timehtml (relativedate .Date) .Date }}
{{ range .Projects }}
{{ if .Logo }}
<a class="flex flex-shrink-0" href="{{ .Url }}">
<img class="avatar ml2" src="{{ .Logo }}">
</a>
{{ end }}
</div>
</div>
{{ if .SmallInfo }}
<a href="{{ .Url }}">{{ timehtml (relativedate .Date) .Date }}</a>
{{ end }}
{{ if .Editable }}
<a href="javascript:;" class="edit ml2">&#9998;</a>
<div class="dn rawdesc">{{ .RawDescription }}</div>
{{ end }}
{{ end }}
</div>
{{/* content */}}
{{ range .EmbedMedia }}
<div class="timeline-content-box mt3 {{ if eq .Type mediaembed }}embed{{ end }} overflow-hidden flex {{ if not (eq .Type mediaunknown) }}timeline-item-bg justify-center{{ end }}">
{{ range .Media }}
<div class="timeline-media mt3 {{ if eq .Type mediaembed }}timeline-embed{{ end }} overflow-hidden flex {{ if not (eq .Type mediaunknown) }}justify-center{{ end }}">
{{ if eq .Type mediaimage }}
<img src="{{ .AssetUrl }}">
{{ else if eq .Type mediavideo }}
@ -72,14 +93,7 @@
{{ end }}
{{ end }}
{{ with .Projects }}
<div class="mt3 flex g2 projects">
{{ range $i, $proj := . }}
<a data-projid="{{ $proj.ID }}" href="{{ $proj.Url }}" class="snippet-project flex flex-row items-center bg-theme-dimmer ph2 pv1">
<img src="{{ $proj.Logo }}" class="db mr1 br1 h1-5" />
<div>{{ $proj.Name }}</div>
</a>
{{ end }}
</div>
{{ with .DiscordMessageUrl }}
<a class="f7 mt3 i" href="{{ . }}" target="_blank">View original message on Discord</a>
{{ end }}
</div>

View File

@ -2,6 +2,7 @@
{{ define "extrahead" }}
<script src="{{ static "js/templates.js" }}"></script>
<script src="{{ static "js/tabs.js" }}"></script>
{{ end }}
{{ define "content" }}
@ -87,31 +88,31 @@
<div class="w5 flex flex-column g2 flex-shrink-0">
{{ if .User }}
<div class="sidebar-card bg--card link--normal">
<div onclick="collapse(event)" class="pa2 flex justify-between items-center pointer">
<div onclick="collapse(event)" class="pa3 flex justify-between items-center pointer">
<span class="f7">Your projects</span>
<span class="sidebar-chevron svgicon-lite rot-180">{{ svg "chevron-down" }}</span>
</div>
<div class="sidebar-card-content">
<div class="ph2 flex flex-column g2">
<div class="ph3 flex flex-column g2">
{{ range .UserProjects }}
{{ template "list-project" . }}
{{ else }}
<div class="f7 pv3 tc c--dim">You have not created any projects.</div>
{{ end }}
</div>
<a class="bt mt2 pa2 flex justify-between" href="{{ .NewProjectUrl }}">
<a class="bt mt3 pa3 flex justify-between" href="{{ .NewProjectUrl }}">
<div>Create new project</div>
<div class="svgicon-lite flex items-center">{{ svg "add" }}</div>
</a>
</div>
</div>
<div class="sidebar-card bg--card link--normal">
<div onclick="collapse(event)" class="pa2 flex justify-between items-center pointer">
<div onclick="collapse(event)" class="pa3 flex justify-between items-center pointer">
<span class="f7">Following</span>
<span class="sidebar-chevron svgicon-lite rot-180">{{ svg "chevron-down" }}</span>
</div>
<div class="sidebar-card-content">
<div class="ph2 pb2 flex flex-column g2">
<div class="ph3 pb3 flex flex-column g2">
{{ range .Following }}
{{ template "list-follow" . }}
{{ else }}
@ -122,11 +123,11 @@
</div>
{{ else }}
<div class="bg--card link--normal">
<div class="pa2 flex flex-column g2">
<div class="pa3 flex flex-column g2">
<div class="b">Join the Handmade Network</div>
<div class="f6 post-content">Share your own Handmade projects with the community.</div>
</div>
<a class="bt pa2 flex justify-between" href="{{ .LoginPageUrl }}">
<a class="bt pa3 flex justify-between" href="{{ .LoginPageUrl }}">
<div>Log in</div>
<div class="svgicon-lite flex items-center">{{ svg "chevron-right" }}</div>
</a>
@ -139,11 +140,40 @@
<!-- Feed -->
<div class="flex flex-column flex-grow-1 overflow-hidden">
<div class="timeline flex flex-column g3">
{{ range .RecentItems }}
{{ template "timeline_item.html" . }}
{{ end }}
TODO: READ MORE LINK
<div id="landing-tabs">
<div class="bb mb2 flex f6">
{{ if .User }}
<div data-tab-button="following" class="tab-button ph3 pv1 pointer">Following</div>
{{ end }}
<div data-tab-button="featured" class="tab-button ph3 pv1 pointer">Featured</div>
<div data-tab-button="recent" class="tab-button ph3 pv1 pointer">Recent</div>
<div data-tab-button="news" class="tab-button ph3 pv1 pointer">News</div>
</div>
<div>
{{ if .User }}
<div data-tab="following" class="timeline flex flex-column g3">
{{ range .FollowingItems }}
{{ template "timeline_item.html" . }}
{{ end }}
</div>
{{ end }}
<div data-tab="featured" class="timeline flex flex-column g3">
{{ range .FeaturedItems }}
{{ template "timeline_item.html" . }}
{{ end }}
</div>
<div data-tab="recent" class="timeline flex flex-column g3">
{{ range .RecentItems }}
{{ template "timeline_item.html" . }}
{{ end }}
</div>
<div data-tab="news" class="timeline flex flex-column g3">
{{ range .NewsItems }}
{{ template "timeline_item.html" . }}
{{ end }}
</div>
TODO: READ MORE LINK
</div>
</div>
</div>
</div>
@ -160,6 +190,8 @@
content.hidden = hide;
chevron.classList.toggle("rot-180", !hide);
}
initTabs(document.querySelector("#landing-tabs"));
</script>
{{ end }}

View File

@ -76,6 +76,9 @@
<body class="{{ join " " .BodyClasses }}">
<div class="bg--main m--center mw-site ph3-m ph4-l">
<div class="notice notice-warn mt3 mb2 white ph3 pv2 br2-ns">
We are currently in the process of converting the website to the new design. Some pages, like this one, are still broken. We appreciate your patience.
</div>
{{ template "header.html" . }}
{{ template "notices.html" .Notices }}
{{ with .Breadcrumbs }}

View File

@ -57,7 +57,7 @@
--theme-color-dimmer: {{ $themeDimmer }};
--theme-color-dimmest: {{ $themeDimmest }};
--timeline-content-background: rgba(255, 255, 255, 0.1);
--timeline-media-background: rgba(255, 255, 255, 0.1);
}
body {

View File

@ -57,7 +57,7 @@
--theme-color-dimmer: {{ $themeDimmer }};
--theme-color-dimmest: {{ $themeDimmest }};
--timeline-content-background: rgba(255, 255, 255, 0.1);
--timeline-media-background: rgba(255, 255, 255, 0.1);
}
body {

View File

@ -58,7 +58,7 @@
--theme-color-dimmer: {{ $themeDimmer }};
--theme-color-dimmest: {{ $themeDimmest }};
--timeline-content-background: rgba(255, 255, 255, 0.1);
--timeline-media-background: rgba(255, 255, 255, 0.1);
}
body {

View File

@ -2,7 +2,6 @@
{{ define "extrahead" }}
{{ template "markdown_previews.html" .TextEditor }}
<script src="{{ static "js/tabs.js" }}"></script>
<script src="{{ static "js/image_selector.js" }}"></script>
<script src="{{ static "js/templates.js" }}"></script>
<script src="{{ static "js/base64.js" }}"></script>

View File

@ -109,6 +109,30 @@ int main() {
<span class="n">GetWindowRect</span><span class="p">(</span> <span class="n">big_window</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">window_rect</span> <span class="p">);</span>
<span class="n">window_rect</span><span class="p">.</span><span class="n">top</span> <span class="o">+=</span> <span class="mi">30</span><span class="p">;</span>
</pre>
<table>
<thead>
<tr>
<th>Items</th>
<th>Expenditure</th>
</tr>
</thead>
<tbody>
<tr>
<th>Donuts</th>
<td>3,000</td>
</tr>
<tr>
<th>Stationery</th>
<td>18,000</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Totals</th>
<td>21,000</td>
</tr>
</tfoot>
</table>
</div>
<h1 class="mt3 mb2">Form styles</h1>
@ -212,7 +236,7 @@ int main() {
<h1 class="mt3 mb2">Timeline items</h1>
<div class="hmn-form pa3 ba b--theme-dim flex flex-column g3">
<div class="hmn-form pa3 ba b--theme-dim flex flex-column g3 mw7">
{{ range .TestTimelineItems }}
{{ template "timeline_item.html" . }}
{{ end }}

View File

@ -1,7 +1,6 @@
{{ template "base-2024.html" . }}
{{ define "extrahead" }}
<script src="{{ static "js/tabs.js" }}"></script>
<script src="{{ static "js/image_selector.js" }}"></script>
{{ end }}

View File

@ -338,9 +338,9 @@ type TimelineItem struct {
Description template.HTML
RawDescription string
EmbedMedia []TimelineItemMedia
Media []TimelineItemMedia
SmallInfo bool
ForumLayout bool
AllowTitleWrap bool
TruncateDescription bool
CanShowcase bool // whether this snippet can be shown in a showcase gallery

View File

@ -188,7 +188,6 @@ func AdminApprovalQueue(c *RequestContext) ResponseData {
}
timelineItem := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Projects, s.Owner, false)
timelineItem.OwnerAvatarUrl = ""
timelineItem.SmallInfo = true
userData.Timeline = append(userData.Timeline, timelineItem)
}
@ -210,7 +209,6 @@ func AdminApprovalQueue(c *RequestContext) ResponseData {
}
timelineItem := PostToTimelineItem(hmndata.UrlContextForProject(&p.Project), lineageBuilder, &p.Post, &p.Thread, &p.Author)
timelineItem.OwnerAvatarUrl = ""
timelineItem.SmallInfo = true
timelineItem.Description = template.HTML(p.CurrentVersion.TextParsed)
userData.Timeline = append(userData.Timeline, timelineItem)
}

View File

@ -16,6 +16,7 @@ func StyleTest(c *RequestContext) ResponseData {
TestTimelineItems: []templates.TimelineItem{
// Forum post
{
ForumLayout: true,
OwnerName: "Cool User",
OwnerAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
Date: time.Now().Add(-5 * time.Second),
@ -28,45 +29,73 @@ func StyleTest(c *RequestContext) ResponseData {
Title: "How can I a website?",
},
// Blog post
// Snippet
// Snippet with image
{
SmallInfo: true,
OwnerName: "Cool User",
OwnerAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
Date: time.Date(2022, 3, 20, 13, 32, 54, 0, time.UTC),
Url: "test",
DiscordMessageUrl: "test",
EmbedMedia: []templates.TimelineItemMedia{
Media: []templates.TimelineItemMedia{
{
Type: templates.TimelineItemMediaTypeImage,
AssetUrl: "https://assets.media.handmade.network/32ff3e7e-1d9c-4740-a062-1f8bec2e44cf/unknown.png",
},
},
Projects: []templates.Project{
{Name: "Cool Project", Logo: "https://assets.media.handmade.network/8c6a3b71-9e91-4bf6-80ef-bc8f3d21b30d/netsim.png"},
},
},
// Snippet with tall image
{
OwnerName: "Cool User",
OwnerAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
Date: time.Date(2022, 3, 20, 13, 32, 54, 0, time.UTC),
Description: "I got my LaGUI working on Android! 😄",
Url: "test",
DiscordMessageUrl: "https://discord.com/channels/239737791225790464/404399251276169217/1245228715407966208",
Media: []templates.TimelineItemMedia{
{
Type: templates.TimelineItemMediaTypeImage,
AssetUrl: "https://assets.media.handmade.network/ea6f914a-ea00-4cbb-bbd7-586b82fdb484/Screenshot_20240529_120344_com.lagui.simplest.jpg",
},
},
},
// Snippet with video
{
OwnerName: "Cool User",
OwnerAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
Date: time.Date(2024, 1, 30, 3, 32, 54, 0, time.UTC),
Url: "test",
Description: "Using my newfound decoding knowledge I started working on a simple video editor. I also tried decoding 16 files at once, which didn't seem to bother my 3080 at all.",
DiscordMessageUrl: "https://discord.com/channels/239737791225790464/404399251276169217/1249562779619168266",
Media: []templates.TimelineItemMedia{
{
Type: templates.TimelineItemMediaTypeVideo,
AssetUrl: "https://assets.media.handmade.network/b122c7be-dc6d-41fe-a5ed-033fe991927e/show16.mp4",
ThumbnailUrl: "https://assets.media.handmade.network/b122c7be-dc6d-41fe-a5ed-033fe991927e/b122c7be-dc6d-41fe-a5ed-033fe991927e_thumb.jpg",
},
},
},
// Snippet with embed
{
SmallInfo: true,
OwnerName: "Cool User",
OwnerAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
Date: time.Date(2021, 4, 3, 1, 44, 54, 0, time.UTC),
Url: "test",
DiscordMessageUrl: "test",
EmbedMedia: []templates.TimelineItemMedia{
Media: []templates.TimelineItemMedia{
youtubeMediaItem("FN9hZcTB16g"),
},
Projects: []templates.Project{
{Name: "Cool Project", Logo: templates.UserAvatarDefaultUrl("light")},
},
},
// Snippet with two images & multiple projects
{
SmallInfo: true,
OwnerName: "Cool User",
OwnerAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
Date: time.Now().Add(-2 * 24 * time.Hour),
Url: "test",
DiscordMessageUrl: "test",
EmbedMedia: []templates.TimelineItemMedia{
Media: []templates.TimelineItemMedia{
{
Type: templates.TimelineItemMediaTypeImage,
AssetUrl: "https://assets.media.handmade.network/979d8850-f6b6-44b4-984e-93be82eb492b/PBR_WIP_20240620_01.png",
@ -77,19 +106,18 @@ func StyleTest(c *RequestContext) ResponseData {
},
},
Projects: []templates.Project{
{Name: "Cool Project", Logo: templates.UserAvatarDefaultUrl("light")},
{Name: "Cool Project", Logo: "https://assets.media.handmade.network/8c6a3b71-9e91-4bf6-80ef-bc8f3d21b30d/netsim.png"},
{Name: "Uncool Project"},
},
},
// Snippet with a video and an image
{
SmallInfo: true,
OwnerName: "Cool User",
OwnerAvatarUrl: templates.UserAvatarDefaultUrl("dark"),
Date: time.Now().Add(-2 * time.Hour),
Url: "test",
DiscordMessageUrl: "test",
EmbedMedia: []templates.TimelineItemMedia{
Media: []templates.TimelineItemMedia{
{
Type: templates.TimelineItemMediaTypeImage,
AssetUrl: "https://assets.media.handmade.network/979d8850-f6b6-44b4-984e-93be82eb492b/PBR_WIP_20240620_01.png",
@ -100,8 +128,7 @@ func StyleTest(c *RequestContext) ResponseData {
},
},
Projects: []templates.Project{
{Name: "Cool Project", Logo: templates.UserAvatarDefaultUrl("light")},
{Name: "Uncool Project"},
{Name: "Project without logo"},
},
},
// Snippet with every type of embed at once

View File

@ -271,7 +271,6 @@ func getLJ2024FeedData(c *RequestContext, maxTimelineItems int) (JamFeedDataLJ20
timelineItems = make([]templates.TimelineItem, 0, len(snippets))
for _, s := range snippets {
timelineItem := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Projects, s.Owner, false)
timelineItem.SmallInfo = true
timelineItems = append(timelineItems, timelineItem)
}
}
@ -451,7 +450,6 @@ func JamFeed2023(c *RequestContext) ResponseData {
timelineItems = make([]templates.TimelineItem, 0, len(snippets))
for _, s := range snippets {
timelineItem := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Projects, s.Owner, false)
timelineItem.SmallInfo = true
timelineItems = append(timelineItems, timelineItem)
}
}
@ -619,7 +617,6 @@ func JamFeed2023_Visibility(c *RequestContext) ResponseData {
timelineItems = make([]templates.TimelineItem, 0, len(snippets))
for _, s := range snippets {
timelineItem := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Projects, s.Owner, false)
timelineItem.SmallInfo = true
timelineItems = append(timelineItems, timelineItem)
}
}
@ -832,7 +829,6 @@ func JamFeed2022(c *RequestContext) ResponseData {
timelineItems = make([]templates.TimelineItem, 0, len(snippets))
for _, s := range snippets {
timelineItem := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Projects, s.Owner, false)
timelineItem.SmallInfo = true
timelineItems = append(timelineItems, timelineItem)
}
}

View File

@ -20,7 +20,6 @@ func Index(c *RequestContext) ResponseData {
type LandingTemplateData struct {
templates.BaseData
NewsPost *templates.TimelineItem
FollowingItems []templates.TimelineItem
FeaturedItems []templates.TimelineItem
RecentItems []templates.TimelineItem
@ -56,6 +55,24 @@ func Index(c *RequestContext) ResponseData {
}
}
featuredProjects, err := hmndata.FetchProjects(c, c.Conn, c.CurrentUser, hmndata.ProjectsQuery{
FeaturedOnly: true,
})
if err != nil {
c.Logger.Warn().Err(err).Msg("failed to fetch featured projects")
}
var featuredProjectIDs []int
for _, p := range featuredProjects {
featuredProjectIDs = append(featuredProjectIDs, p.Project.ID)
}
featuredItems, err = FetchTimeline(c, c.Conn, c.CurrentUser, TimelineQuery{
ProjectIDs: featuredProjectIDs,
Limit: 100,
})
if err != nil {
c.Logger.Warn().Err(err).Msg("failed to fetch featured feed")
}
recentItems, err = FetchTimeline(c, c.Conn, c.CurrentUser, TimelineQuery{
Limit: 100,
})
@ -63,27 +80,24 @@ func Index(c *RequestContext) ResponseData {
c.Logger.Warn().Err(err).Msg("failed to fetch recent feed")
}
c.Perf.StartBlock("SQL", "Get news")
newsThreads, err := hmndata.FetchThreads(c, c.Conn, c.CurrentUser, hmndata.ThreadsQuery{
ProjectIDs: []int{models.HMNProjectID},
ThreadTypes: []models.ThreadType{models.ThreadTypeProjectBlogPost},
Limit: 1,
ProjectIDs: []int{models.HMNProjectID},
ThreadTypes: []models.ThreadType{models.ThreadTypeProjectBlogPost},
Limit: 100,
OrderByCreated: true,
})
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch news post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch news threads"))
}
var newsPostItem *templates.TimelineItem
if len(newsThreads) > 0 {
t := newsThreads[0]
item := PostToTimelineItem(hmndata.UrlContextForProject(&t.Project), lineageBuilder, &t.FirstPost, &t.Thread, t.FirstPostAuthor)
for _, t := range newsThreads {
item := PostToTimelineItem(c.UrlContext, lineageBuilder, &t.FirstPost, &t.Thread, t.FirstPostAuthor)
item.Breadcrumbs = nil
item.TypeTitle = ""
item.AllowTitleWrap = true
item.Description = template.HTML(t.FirstPostCurrentVersion.TextParsed)
item.AllowTitleWrap = true
item.TruncateDescription = true
newsPostItem = &item
newsItems = append(newsItems, item)
}
c.Perf.EndBlock()
var projects []templates.Project
if c.CurrentUser != nil {
@ -117,7 +131,6 @@ func Index(c *RequestContext) ResponseData {
err = res.WriteTemplate("landing.html", LandingTemplateData{
BaseData: baseData,
NewsPost: newsPostItem,
FollowingItems: followingItems,
FeaturedItems: featuredItems,
RecentItems: recentItems,

View File

@ -58,7 +58,6 @@ func Snippet(c *RequestContext) ResponseData {
canEdit := (c.CurrentUser != nil && (c.CurrentUser.IsStaff || c.CurrentUser.ID == s.Owner.ID))
snippet := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Projects, s.Owner, canEdit)
snippet.SmallInfo = true
opengraph := []templates.OpenGraphItem{
{Property: "og:site_name", Value: "Handmade Network"},
@ -68,8 +67,8 @@ func Snippet(c *RequestContext) ResponseData {
{Property: "og:description", Value: string(snippet.Description)},
}
if len(snippet.EmbedMedia) > 0 {
media := snippet.EmbedMedia[0]
if len(snippet.Media) > 0 {
media := snippet.Media[0]
switch media.Type {
case templates.TimelineItemMediaTypeImage:

View File

@ -148,7 +148,6 @@ func FetchTimeline(ctx context.Context, conn db.ConnOrTx, currentUser *models.Us
s.Owner,
false,
)
item.SmallInfo = true
timelineItems = append(timelineItems, item)
}
@ -300,6 +299,8 @@ func PostToTimelineItem(
OwnerAvatarUrl: ownerTmpl.AvatarUrl,
OwnerName: ownerTmpl.Name,
OwnerUrl: ownerTmpl.ProfileUrl,
ForumLayout: true,
}
if typeTitles, ok := TimelineTypeTitleMap[post.ThreadType]; ok {
@ -349,7 +350,7 @@ func TwitchStreamToTimelineItem(
OwnerName: ownerName,
OwnerUrl: ownerUrl,
SmallInfo: true,
ForumLayout: true,
}
return item
@ -382,26 +383,26 @@ func SnippetToTimelineItem(
if asset != nil {
if strings.HasPrefix(asset.MimeType, "image/") {
item.EmbedMedia = append(item.EmbedMedia, imageMediaItem(asset))
item.Media = append(item.Media, imageMediaItem(asset))
} else if strings.HasPrefix(asset.MimeType, "video/") {
item.EmbedMedia = append(item.EmbedMedia, videoMediaItem(asset))
item.Media = append(item.Media, videoMediaItem(asset))
} else if strings.HasPrefix(asset.MimeType, "audio/") {
item.EmbedMedia = append(item.EmbedMedia, audioMediaItem(asset))
item.Media = append(item.Media, audioMediaItem(asset))
} else {
item.EmbedMedia = append(item.EmbedMedia, unknownMediaItem(asset))
item.Media = append(item.Media, unknownMediaItem(asset))
}
}
if snippet.Url != nil {
url := *snippet.Url
if videoId := getYoutubeVideoID(url); videoId != "" {
item.EmbedMedia = append(item.EmbedMedia, youtubeMediaItem(videoId))
item.Media = append(item.Media, youtubeMediaItem(videoId))
item.CanShowcase = false
}
}
if len(item.EmbedMedia) == 0 ||
(len(item.EmbedMedia) > 0 && (item.EmbedMedia[0].Width == 0 || item.EmbedMedia[0].Height == 0)) {
if len(item.Media) == 0 ||
(len(item.Media) > 0 && (item.Media[0].Width == 0 || item.Media[0].Height == 0)) {
item.CanShowcase = false
}

View File

@ -14,6 +14,7 @@
- [x] column
- [ ] content
- [ ] description
- [ ] c--dim and friends
- [ ] Re-evaluate form styles
- [ ] theme-color-light is used only for buttons
- [x] center-layout vs. margin-center
@ -55,4 +56,4 @@
- TikTok?
- Trello?
- [ ] Handle empty avatar URLs correctly in various places (render as theme-dependent default)
- [ ] Resolve TODO(redesign) comments
- [ ] Resolve TODO(redesign) comments