Remove stray console.log and update translations.

Update themes endpoint and filter unmatched commits.
This commit is contained in:
Paul 2021-09-09 22:39:17 +01:00
parent efbbb6f1aa
commit 048267b419
6 changed files with 196 additions and 158 deletions

2
.env
View file

@ -1,2 +1,2 @@
VITE_API_URL=https://api.revolt.chat VITE_API_URL=https://api.revolt.chat
VITE_THEMES_URL=https://static.revolt.chat/themes VITE_THEMES_URL=https://themes.revolt.chat

View file

@ -1,2 +1,2 @@
VITE_API_URL=__API_URL__ VITE_API_URL=__API_URL__
VITE_THEMES_URL=https://static.revolt.chat/themes VITE_THEMES_URL=https://themes.revolt.chat

2
external/lang vendored

@ -1 +1 @@
Subproject commit 2d5b96a5c72bb706b73e9b67d5be395810a18c15 Subproject commit edebbe8a1d720b2ecbedbf137e2e7c2f2e3d1e13

View file

@ -44,7 +44,7 @@ if (typeof window !== "undefined") {
if (code) { if (code) {
navigator.clipboard.writeText(code.textContent?.trim() ?? ""); navigator.clipboard.writeText(code.textContent?.trim() ?? "");
} }
} catch (e) { } } catch (e) {}
}; };
} }
@ -150,8 +150,8 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
`<@${element.dataset.mentionId}>`, `<@${element.dataset.mentionId}>`,
"mention", "mention",
); );
ev.preventDefault() ev.preventDefault();
return return;
} }
case "channel_mention": { case "channel_mention": {
internalEmit( internalEmit(
@ -160,8 +160,8 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
`<#${element.dataset.mentionId}>`, `<#${element.dataset.mentionId}>`,
"channel_mention", "channel_mention",
); );
ev.preventDefault() ev.preventDefault();
return return;
} }
} }
} }
@ -194,7 +194,6 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
element.removeAttribute("target"); element.removeAttribute("target");
const link = determineLink(element.href); const link = determineLink(element.href);
console.log(link)
switch (link.type) { switch (link.type) {
case "profile": { case "profile": {
element.setAttribute( element.setAttribute(
@ -203,20 +202,20 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
); );
element.setAttribute( element.setAttribute(
"data-mention-id", "data-mention-id",
link.id link.id,
) );
break; break;
} }
case "navigate": { case "navigate": {
if (link.navigation_type === 'channel') { if (link.navigation_type === "channel") {
element.setAttribute( element.setAttribute(
"data-type", "data-type",
"channel_mention", "channel_mention",
); );
element.setAttribute( element.setAttribute(
"data-mention-id", "data-mention-id",
link.channel_id link.channel_id,
) );
} }
break; break;
} }

View file

@ -1,7 +1,12 @@
type LinkType = type LinkType =
| { type: "profile"; id: string } | { type: "profile"; id: string }
| { type: "navigate"; path: string; navigation_type?: null } | { type: "navigate"; path: string; navigation_type?: null }
| { type: "navigate"; path: string; navigation_type: 'channel'; channel_id: string } | {
type: "navigate";
path: string;
navigation_type: "channel";
channel_id: string;
}
| { type: "external"; href: string; url: URL } | { type: "external"; href: string; url: URL }
| { type: "none" }; | { type: "none" };
@ -12,7 +17,8 @@ const ALLOWED_ORIGINS = [
"local.revolt.chat", "local.revolt.chat",
]; ];
const CHANNEL_PATH_RE = /^\/server\/[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}\/channel\/[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/ const CHANNEL_PATH_RE =
/^\/server\/[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}\/channel\/[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/;
export function determineLink(href?: string): LinkType { export function determineLink(href?: string): LinkType {
let internal, let internal,
@ -30,9 +36,13 @@ export function determineLink(href?: string): LinkType {
return { type: "profile", id }; return { type: "profile", id };
} }
} else { } else {
console.log(path) if (CHANNEL_PATH_RE.test(path)) {
if(CHANNEL_PATH_RE.test(path)) { return {
return { type: 'navigate', path, navigation_type: 'channel', channel_id: path.slice(43) } type: "navigate",
path,
navigation_type: "channel",
channel_id: path.slice(43),
};
} }
return { type: "navigate", path }; return { type: "navigate", path };
} }

View file

@ -1,178 +1,207 @@
import { useEffect, useState } from "preact/hooks" import styled from "styled-components";
import styled from "styled-components"
import Tip from "../../../components/ui/Tip" import { useEffect, useState } from "preact/hooks";
import { Theme, generateVariables } from '../../../context/Theme'
import { dispatch } from "../../../redux" import { dispatch } from "../../../redux";
import { Theme, generateVariables } from "../../../context/Theme";
import Tip from "../../../components/ui/Tip";
import previewPath from "../assets/preview.svg";
import { GIT_REVISION } from "../../../revision";
export const fetchManifest = (): Promise<Manifest> => export const fetchManifest = (): Promise<Manifest> =>
fetch(`${import.meta.env.VITE_THEMES_URL}/manifest.json`).then(res => res.json()) fetch(`${import.meta.env.VITE_THEMES_URL}/manifest.json`).then((res) =>
res.json(),
);
export const fetchTheme = (slug: string): Promise<Theme> => export const fetchTheme = (slug: string): Promise<Theme> =>
fetch(`${import.meta.env.VITE_THEMES_URL}/theme_${slug}.json`).then(res => res.json()) fetch(`${import.meta.env.VITE_THEMES_URL}/theme_${slug}.json`).then((res) =>
res.json(),
);
interface ThemeMetadata { interface ThemeMetadata {
name: string, name: string;
creator: string, creator: string;
description: string commit?: string;
description: string;
} }
type Manifest = { type Manifest = {
generated: string, generated: string;
themes: Record<string, ThemeMetadata> themes: Record<string, ThemeMetadata>;
} };
// TODO: ability to preview / display the settings set like in the appearance pane // TODO: ability to preview / display the settings set like in the appearance pane
const ThemeInfo = styled.article` const ThemeInfo = styled.article`
display: grid; display: grid;
grid: grid:
"preview name creator" min-content "preview name creator" min-content
"preview desc desc" 1fr "preview desc desc" 1fr
/ 200px 1fr 1fr; / 200px 1fr 1fr;
gap: 0.5rem 1rem; gap: 0.5rem 1rem;
padding: 1rem; padding: 1rem;
border-radius: var(--border-radius); border-radius: var(--border-radius);
background: var(--secondary-background); background: var(--secondary-background);
&[data-loaded] {
.preview {
opacity: 1;
}
}
&[data-loaded] {
.preview { .preview {
opacity: 1; grid-area: preview;
} aspect-ratio: 323 / 202;
}
.preview { background-color: var(--secondary-background);
grid-area: preview; border-radius: calc(var(--border-radius) / 2);
aspect-ratio: 323 / 202;
background-color: var(--secondary-background); // prep style for later
border-radius: calc(var(--border-radius) / 2); outline: 3px solid transparent;
// prep style for later // hide random svg parts, crop border on firefox
outline: 3px solid transparent; overflow: hidden;
// hide random svg parts, crop border on firefox // hide until loaded
overflow: hidden; opacity: 0;
// hide until loaded // style button
opacity: 0; border: 0;
margin: 0;
padding: 0;
// style button transition: 0.25s opacity, 0.25s outline;
border: 0;
margin: 0;
padding: 0;
transition: 0.25s opacity, 0.25s outline; > * {
grid-area: 1 / 1;
}
> * { svg {
grid-area: 1 / 1; height: 100%;
width: 100%;
object-fit: contain;
}
&:hover,
&:active,
&:focus-visible {
outline: 3px solid var(--tertiary-background);
}
} }
svg { .name {
height: 100%; grid-area: name;
width: 100%; margin: 0;
object-fit: contain;
} }
&:hover, &:active, &:focus-visible { .creator {
outline: 3px solid var(--tertiary-background); grid-area: creator;
justify-self: end;
font-size: 0.75rem;
} }
}
.name { .description {
grid-area: name; grid-area: desc;
margin: 0; }
} `;
.creator {
grid-area: creator;
justify-self: end;
font-size: 0.75rem;
}
.description {
grid-area: desc;
}
`
const ThemeList = styled.div` const ThemeList = styled.div`
display: grid; display: grid;
gap: 1rem; gap: 1rem;
` `;
import previewPath from '../assets/preview.svg'
const ThemedSVG = styled.svg<{ theme: Theme }>` const ThemedSVG = styled.svg<{ theme: Theme }>`
${props => props.theme && generateVariables(props.theme)} ${(props) => props.theme && generateVariables(props.theme)}
` `;
type ThemePreviewProps = Omit<JSX.HTMLAttributes<SVGSVGElement>, "as"> & { type ThemePreviewProps = Omit<JSX.HTMLAttributes<SVGSVGElement>, "as"> & {
slug?: string, slug?: string;
theme?: Theme theme?: Theme;
onThemeLoaded?: (theme: Theme) => void onThemeLoaded?: (theme: Theme) => void;
}; };
const ThemePreview = ({ theme, ...props }: ThemePreviewProps) => { const ThemePreview = ({ theme, ...props }: ThemePreviewProps) => {
return <ThemedSVG {...props} theme={theme} width="323" height="202" aria-hidden="true" data-loaded={!!theme}> return (
<use href={`${previewPath}#preview`} width="100%" height="100%" /> <ThemedSVG
</ThemedSVG > {...props}
} theme={theme}
width="323"
height="202"
aria-hidden="true"
data-loaded={!!theme}>
<use href={`${previewPath}#preview`} width="100%" height="100%" />
</ThemedSVG>
);
};
const ThemeShopRoot = styled.div` const ThemeShopRoot = styled.div`
display: grid; display: grid;
gap: 1rem; gap: 1rem;
` `;
export function ThemeShop() { export function ThemeShop() {
// setThemeList is for adding more / lazy loading in the future // setThemeList is for adding more / lazy loading in the future
const [themeList, setThemeList] = useState<[string, ThemeMetadata][] | null>(null); const [themeList, setThemeList] = useState<
const [themeData, setThemeData] = useState<Record<string, Theme>>({}); [string, ThemeMetadata][] | null
>(null);
const [themeData, setThemeData] = useState<Record<string, Theme>>({});
async function fetchThemeList() { async function fetchThemeList() {
const manifest = await fetchManifest() const manifest = await fetchManifest();
setThemeList(Object.entries(manifest.themes)) setThemeList(
} Object.entries(manifest.themes).filter((x) =>
x[1].commit ? x[1].commit === GIT_REVISION : true,
),
);
}
async function getTheme(slug: string) { async function getTheme(slug: string) {
const theme = await fetchTheme(slug); const theme = await fetchTheme(slug);
setThemeData(data => ({ ...data, [slug]: theme })) setThemeData((data) => ({ ...data, [slug]: theme }));
} }
useEffect(() => { useEffect(() => {
fetchThemeList() fetchThemeList();
}, []) }, []);
useEffect(() => { useEffect(() => {
themeList?.forEach(([slug]) => { themeList?.forEach(([slug]) => {
getTheme(slug) getTheme(slug);
}) });
}, [themeList]) }, [themeList]);
return (<ThemeShopRoot> return (
<Tip warning>This section is under construction.</Tip> <ThemeShopRoot>
<ThemeList> <Tip warning hideSeparator>
{themeList?.map(([slug, theme]) => ( This section is under construction.
<ThemeInfo key={slug} data-loaded={Reflect.has(themeData, slug)}> </Tip>
<h2 class="name">{theme.name}</h2> <ThemeList>
{/* Maybe id's of the users should be included as well / instead? */} {themeList?.map(([slug, theme]) => (
<div class="creator">by {theme.creator}</div> <ThemeInfo
<div class="description">{theme.description}</div> key={slug}
<button data-loaded={Reflect.has(themeData, slug)}>
class="preview" <h2 class="name">{theme.name}</h2>
onClick={() => dispatch({ {/* Maybe id's of the users should be included as well / instead? */}
type: "SETTINGS_SET_THEME", <div class="creator">by {theme.creator}</div>
theme: { <div class="description">{theme.description}</div>
custom: themeData[slug], <button
} class="preview"
})} onClick={() =>
> dispatch({
<ThemePreview type: "SETTINGS_SET_THEME",
slug={slug} theme: {
theme={themeData[slug]} custom: themeData[slug],
/> },
</button> })
</ThemeInfo> }>
))} <ThemePreview slug={slug} theme={themeData[slug]} />
</ThemeList> </button>
</ThemeShopRoot>) </ThemeInfo>
))}
</ThemeList>
</ThemeShopRoot>
);
} }