forked from mystiq/hydrogen-web
Merge pull request #7 from vector-im/bwindels/theming
Initial theming support
This commit is contained in:
commit
5183615994
55 changed files with 778 additions and 245 deletions
27
index.html
27
index.html
|
@ -9,38 +9,17 @@
|
||||||
<meta name="apple-mobile-web-app-title" content="Hydrogen Chat">
|
<meta name="apple-mobile-web-app-title" content="Hydrogen Chat">
|
||||||
<meta name="description" content="A matrix chat application">
|
<meta name="description" content="A matrix chat application">
|
||||||
<link rel="stylesheet" type="text/css" href="src/ui/web/css/main.css">
|
<link rel="stylesheet" type="text/css" href="src/ui/web/css/main.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="src/ui/web/css/themes/element/theme.css" title="Element Theme">
|
||||||
|
<link rel="alternate stylesheet" type="text/css" href="src/ui/web/css/themes/bubbles/theme.css" title="Bubbles Theme">
|
||||||
</head>
|
</head>
|
||||||
<body class="hydrogen">
|
<body class="hydrogen">
|
||||||
<script id="version" type="disabled">
|
<script id="version" type="disabled">
|
||||||
</script>
|
|
||||||
<script id="phone-debug-pre" type="disabled">
|
|
||||||
window.DEBUG = true;
|
|
||||||
window.debugConsoleBuffer = "";
|
|
||||||
console.error = (...params) => {
|
|
||||||
const lastLines = "...\n" + window.debugConsoleBuffer.split("\n").slice(-10).join("\n");
|
|
||||||
// window.debugConsoleBuffer = window.debugConsoleBuffer + "ERR " + params.join(" ") + "\n";
|
|
||||||
// const location = new Error().stack.split("\n")[2];
|
|
||||||
alert(params.join(" ") +"\n...\n" + lastLines);
|
|
||||||
};
|
|
||||||
console.log = console.info = console.warn = (...params) => {
|
|
||||||
window.debugConsoleBuffer = window.debugConsoleBuffer + params.join(" ") + "\n";
|
|
||||||
};
|
|
||||||
window.HYDROGEN_VERSION = "%%VERSION%%";
|
window.HYDROGEN_VERSION = "%%VERSION%%";
|
||||||
</script>
|
</script>
|
||||||
<script id="main" type="module">
|
<script id="main" type="module">
|
||||||
import main from "./src/main.js";
|
import {main} from "./src/main.js";
|
||||||
main(document.body);
|
main(document.body);
|
||||||
</script>
|
</script>
|
||||||
<script id="phone-debug-post" type="disabled">
|
|
||||||
setTimeout(() => {
|
|
||||||
const showlogs = document.getElementById("showlogs");
|
|
||||||
showlogs.addEventListener("click", () => {
|
|
||||||
const lastLines = "...\n" + window.debugConsoleBuffer.split("\n").slice(-20).join("\n");
|
|
||||||
alert(lastLines);
|
|
||||||
}, true);
|
|
||||||
showlogs.innerText = "Show last 20 log lines";
|
|
||||||
}, 5000);
|
|
||||||
</script>
|
|
||||||
<script id="service-worker" type="disabled">
|
<script id="service-worker" type="disabled">
|
||||||
if('serviceWorker' in navigator) {
|
if('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker.register('sw.js')
|
navigator.serviceWorker.register('sw.js')
|
||||||
|
|
|
@ -43,6 +43,7 @@ const PROJECT_NAME = "Hydrogen Chat";
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
const projectDir = path.join(__dirname, "../");
|
const projectDir = path.join(__dirname, "../");
|
||||||
|
const cssDir = path.join(projectDir, "src/ui/web/css/");
|
||||||
const targetDir = path.join(projectDir, "target");
|
const targetDir = path.join(projectDir, "target");
|
||||||
|
|
||||||
const {debug, noOffline, legacy} = process.argv.reduce((params, param) => {
|
const {debug, noOffline, legacy} = process.argv.reduce((params, param) => {
|
||||||
|
@ -67,31 +68,80 @@ async function build() {
|
||||||
if (legacy) {
|
if (legacy) {
|
||||||
bundleName = `${PROJECT_ID}-legacy.js`;
|
bundleName = `${PROJECT_ID}-legacy.js`;
|
||||||
}
|
}
|
||||||
await buildHtml(version, bundleName);
|
|
||||||
|
|
||||||
|
const devHtml = await fs.readFile(path.join(projectDir, "index.html"), "utf8");
|
||||||
|
const doc = cheerio.load(devHtml);
|
||||||
|
const themes = [];
|
||||||
|
findThemes(doc, themeName => {
|
||||||
|
themes.push(themeName);
|
||||||
|
});
|
||||||
|
|
||||||
|
// also creates the directories where the theme css bundles are placed in,
|
||||||
|
// so do it first
|
||||||
|
const themeAssets = await copyThemeAssets(themes, legacy);
|
||||||
|
|
||||||
|
await buildHtml(doc, version, bundleName);
|
||||||
if (legacy) {
|
if (legacy) {
|
||||||
await buildJsLegacy(bundleName);
|
await buildJsLegacy(bundleName);
|
||||||
await buildCssLegacy();
|
|
||||||
} else {
|
} else {
|
||||||
await buildJs(bundleName);
|
await buildJs(bundleName);
|
||||||
await buildCss();
|
|
||||||
}
|
}
|
||||||
|
await buildCssBundles(legacy ? buildCssLegacy : buildCss, themes);
|
||||||
if (offline) {
|
if (offline) {
|
||||||
await buildOffline(version, bundleName);
|
await buildOffline(version, bundleName, themeAssets);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`built ${PROJECT_ID}${legacy ? " legacy" : ""} ${version} successfully`);
|
console.log(`built ${PROJECT_ID}${legacy ? " legacy" : ""} ${version} successfully`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildHtml(version, bundleName) {
|
async function findThemes(doc, callback) {
|
||||||
|
doc("link[rel~=stylesheet][title]").each((i, el) => {
|
||||||
|
const theme = doc(el);
|
||||||
|
const href = theme.attr("href");
|
||||||
|
const themesPrefix = "/themes/";
|
||||||
|
const prefixIdx = href.indexOf(themesPrefix);
|
||||||
|
if (prefixIdx !== -1) {
|
||||||
|
const themeNameStart = prefixIdx + themesPrefix.length;
|
||||||
|
const themeNameEnd = href.indexOf("/", themeNameStart);
|
||||||
|
const themeName = href.substr(themeNameStart, themeNameEnd - themeNameStart);
|
||||||
|
callback(themeName, theme);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function copyThemeAssets(themes, legacy) {
|
||||||
|
const assets = [];
|
||||||
|
// create theme directories and copy assets
|
||||||
|
await fs.mkdir(path.join(targetDir, "themes"));
|
||||||
|
for (const theme of themes) {
|
||||||
|
assets.push(`themes/${theme}/bundle.css`);
|
||||||
|
const themeDstFolder = path.join(targetDir, `themes/${theme}`);
|
||||||
|
await fs.mkdir(themeDstFolder);
|
||||||
|
const themeSrcFolder = path.join(cssDir, `themes/${theme}`);
|
||||||
|
await copyFolder(themeSrcFolder, themeDstFolder, file => {
|
||||||
|
const isUnneededFont = legacy ? file.endsWith(".woff2") : file.endsWith(".woff");
|
||||||
|
if (!file.endsWith(".css") && !isUnneededFont) {
|
||||||
|
assets.push(file.substr(cssDir.length));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return assets;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildHtml(doc, version, bundleName) {
|
||||||
// transform html file
|
// transform html file
|
||||||
const devHtml = await fs.readFile(path.join(projectDir, "index.html"), "utf8");
|
// change path to main.css to css bundle
|
||||||
const doc = cheerio.load(devHtml);
|
doc("link[rel=stylesheet]:not([title])").attr("href", `${PROJECT_ID}.css`);
|
||||||
doc("link[rel=stylesheet]").attr("href", `${PROJECT_ID}.css`);
|
// change paths to all theme stylesheets
|
||||||
|
findThemes(doc, (themeName, theme) => {
|
||||||
|
theme.attr("href", `themes/${themeName}/bundle.css`);
|
||||||
|
});
|
||||||
doc("script#main").replaceWith(
|
doc("script#main").replaceWith(
|
||||||
`<script type="text/javascript" src="${bundleName}"></script>` +
|
`<script type="text/javascript" src="${bundleName}"></script>` +
|
||||||
`<script type="text/javascript">${PROJECT_ID}Bundle.main(document.body);</script>`);
|
`<script type="text/javascript">${PROJECT_ID}Bundle.main(document.body);</script>`);
|
||||||
removeOrEnableScript(doc("script#phone-debug-pre"), debug);
|
|
||||||
removeOrEnableScript(doc("script#phone-debug-post"), debug);
|
|
||||||
removeOrEnableScript(doc("script#service-worker"), offline);
|
removeOrEnableScript(doc("script#service-worker"), offline);
|
||||||
|
|
||||||
const versionScript = doc("script#version");
|
const versionScript = doc("script#version");
|
||||||
|
@ -146,9 +196,17 @@ async function buildJsLegacy(bundleName) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildOffline(version, bundleName) {
|
async function buildOffline(version, bundleName, themeAssets) {
|
||||||
|
const {offlineAssets, cacheAssets} = themeAssets.reduce((result, asset) => {
|
||||||
|
if (asset.endsWith(".css")) {
|
||||||
|
result.offlineAssets.push(asset);
|
||||||
|
} else {
|
||||||
|
result.cacheAssets.push(asset);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}, {offlineAssets: [], cacheAssets: []});
|
||||||
// write offline availability
|
// write offline availability
|
||||||
const offlineFiles = [bundleName, `${PROJECT_ID}.css`, "index.html", "icon-192.png"];
|
const offlineFiles = [bundleName, `${PROJECT_ID}.css`, "index.html", "icon-192.png"].concat(offlineAssets);
|
||||||
|
|
||||||
// write appcache manifest
|
// write appcache manifest
|
||||||
const manifestLines = [
|
const manifestLines = [
|
||||||
|
@ -164,7 +222,8 @@ async function buildOffline(version, bundleName) {
|
||||||
// write service worker
|
// write service worker
|
||||||
let swSource = await fs.readFile(path.join(projectDir, "src/service-worker.template.js"), "utf8");
|
let swSource = await fs.readFile(path.join(projectDir, "src/service-worker.template.js"), "utf8");
|
||||||
swSource = swSource.replace(`"%%VERSION%%"`, `"${version}"`);
|
swSource = swSource.replace(`"%%VERSION%%"`, `"${version}"`);
|
||||||
swSource = swSource.replace(`"%%FILES%%"`, JSON.stringify(offlineFiles));
|
swSource = swSource.replace(`"%%OFFLINE_FILES%%"`, JSON.stringify(offlineFiles));
|
||||||
|
swSource = swSource.replace(`"%%CACHE_FILES%%"`, JSON.stringify(cacheAssets));
|
||||||
await fs.writeFile(path.join(targetDir, "sw.js"), swSource, "utf8");
|
await fs.writeFile(path.join(targetDir, "sw.js"), swSource, "utf8");
|
||||||
// write web manifest
|
// write web manifest
|
||||||
const webManifest = {
|
const webManifest = {
|
||||||
|
@ -180,25 +239,31 @@ async function buildOffline(version, bundleName) {
|
||||||
await fs.writeFile(path.join(targetDir, "icon-192.png"), icon);
|
await fs.writeFile(path.join(targetDir, "icon-192.png"), icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildCss() {
|
async function buildCssBundles(buildFn, themes) {
|
||||||
// create css bundle
|
const cssMainFile = path.join(cssDir, "main.css");
|
||||||
const cssMainFile = path.join(projectDir, "src/ui/web/css/main.css");
|
await buildFn(cssMainFile, path.join(targetDir, `${PROJECT_ID}.css`));
|
||||||
const preCss = await fs.readFile(cssMainFile, "utf8");
|
for (const theme of themes) {
|
||||||
|
await buildFn(
|
||||||
|
path.join(cssDir, `themes/${theme}/theme.css`),
|
||||||
|
path.join(targetDir, `themes/${theme}/bundle.css`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildCss(entryPath, bundlePath) {
|
||||||
|
const preCss = await fs.readFile(entryPath, "utf8");
|
||||||
const cssBundler = postcss([postcssImport]);
|
const cssBundler = postcss([postcssImport]);
|
||||||
const result = await cssBundler.process(preCss, {from: cssMainFile});
|
const result = await cssBundler.process(preCss, {from: entryPath});
|
||||||
await fs.writeFile(path.join(targetDir, `${PROJECT_ID}.css`), result.css, "utf8");
|
await fs.writeFile(bundlePath, result.css, "utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildCssLegacy() {
|
async function buildCssLegacy(entryPath, bundlePath) {
|
||||||
// create css bundle
|
const preCss = await fs.readFile(entryPath, "utf8");
|
||||||
const cssMainFile = path.join(projectDir, "src/ui/web/css/main.css");
|
|
||||||
const preCss = await fs.readFile(cssMainFile, "utf8");
|
|
||||||
const cssBundler = postcss([postcssImport, cssvariables(), flexbugsFixes()]);
|
const cssBundler = postcss([postcssImport, cssvariables(), flexbugsFixes()]);
|
||||||
const result = await cssBundler.process(preCss, {from: cssMainFile});
|
const result = await cssBundler.process(preCss, {from: entryPath});
|
||||||
await fs.writeFile(path.join(targetDir, `${PROJECT_ID}.css`), result.css, "utf8");
|
await fs.writeFile(bundlePath, result.css, "utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function removeOrEnableScript(scriptNode, enable) {
|
function removeOrEnableScript(scriptNode, enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
scriptNode.attr("type", "text/javascript");
|
scriptNode.attr("type", "text/javascript");
|
||||||
|
@ -209,9 +274,7 @@ function removeOrEnableScript(scriptNode, enable) {
|
||||||
|
|
||||||
async function removeDirIfExists(targetDir) {
|
async function removeDirIfExists(targetDir) {
|
||||||
try {
|
try {
|
||||||
const files = await fs.readdir(targetDir);
|
await fs.rmdir(targetDir, {recursive: true});
|
||||||
await Promise.all(files.map(filename => fs.unlink(path.join(targetDir, filename))));
|
|
||||||
await fs.rmdir(targetDir);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code !== "ENOENT") {
|
if (err.code !== "ENOENT") {
|
||||||
throw err;
|
throw err;
|
||||||
|
@ -219,4 +282,18 @@ async function removeDirIfExists(targetDir) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function copyFolder(srcRoot, dstRoot, filter) {
|
||||||
|
const dirEnts = await fs.readdir(srcRoot, {withFileTypes: true});
|
||||||
|
for (const dirEnt of dirEnts) {
|
||||||
|
const dstPath = path.join(dstRoot, dirEnt.name);
|
||||||
|
const srcPath = path.join(srcRoot, dirEnt.name);
|
||||||
|
if (dirEnt.isDirectory()) {
|
||||||
|
await fs.mkdir(dstPath);
|
||||||
|
await copyFolder(srcPath, dstPath, filter);
|
||||||
|
} else if (dirEnt.isFile() && filter(srcPath)) {
|
||||||
|
await fs.copyFile(srcPath, dstPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
build().catch(err => console.error(err));
|
build().catch(err => console.error(err));
|
||||||
|
|
|
@ -15,13 +15,17 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const VERSION = "%%VERSION%%";
|
const VERSION = "%%VERSION%%";
|
||||||
const FILES = "%%FILES%%";
|
const OFFLINE_FILES = "%%OFFLINE_FILES%%";
|
||||||
const cacheName = `brawl-${VERSION}`;
|
// TODO: cache these files when requested
|
||||||
|
// The difficulty is that these are relative filenames, and we don't have access to document.baseURI
|
||||||
|
// Clients.match({type: "window"}).url and assume they are all the same? they really should be ... safari doesn't support this though
|
||||||
|
const CACHE_FILES = "%%CACHE_FILES%%";
|
||||||
|
const cacheName = `hydrogen-${VERSION}`;
|
||||||
|
|
||||||
self.addEventListener('install', function(e) {
|
self.addEventListener('install', function(e) {
|
||||||
e.waitUntil(
|
e.waitUntil(
|
||||||
caches.open(cacheName).then(function(cache) {
|
caches.open(cacheName).then(function(cache) {
|
||||||
return cache.addAll(FILES);
|
return cache.addAll(OFFLINE_FILES);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -18,7 +19,6 @@ limitations under the License.
|
||||||
--avatar-size: 32px;
|
--avatar-size: 32px;
|
||||||
width: var(--avatar-size);
|
width: var(--avatar-size);
|
||||||
height: var(--avatar-size);
|
height: var(--avatar-size);
|
||||||
border-radius: 100px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
|
@ -29,8 +29,6 @@ limitations under the License.
|
||||||
font-size: calc(var(--avatar-size) * 0.6);
|
font-size: calc(var(--avatar-size) * 0.6);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
letter-spacing: calc(var(--avatar-size) * -0.05);
|
letter-spacing: calc(var(--avatar-size) * -0.05);
|
||||||
background: white;
|
|
||||||
color: black;
|
|
||||||
speak: none;
|
speak: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
src/ui/web/css/font.css
Normal file
15
src/ui/web/css/font.css
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/** from https://gist.github.com/mfornos/9991865 */
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'emoji';
|
||||||
|
src: local('Apple Color Emoji'),
|
||||||
|
local('Segoe UI Emoji'),
|
||||||
|
local('Segoe UI Symbol'),
|
||||||
|
local('Noto Color Emoji'),
|
||||||
|
local('Android Emoji'),
|
||||||
|
local('EmojiSymbols'),
|
||||||
|
local('Symbola');
|
||||||
|
|
||||||
|
/* Emoji unicode blocks */
|
||||||
|
unicode-range: U+1F300-1F5FF, U+1F600-1F64F, U+1F680-1F6FF, U+2600-26FF;
|
||||||
|
}
|
26
src/ui/web/css/form.css
Normal file
26
src/ui/web/css/form.css
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.form > div {
|
||||||
|
margin: 0.4em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form input {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -17,9 +18,6 @@ limitations under the License.
|
||||||
html {
|
html {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionView {
|
.SessionView {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -16,8 +16,6 @@ limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
.LeftPanel {
|
.LeftPanel {
|
||||||
background: #333;
|
|
||||||
color: white;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
}
|
}
|
||||||
|
@ -29,24 +27,10 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.LeftPanel li {
|
.LeftPanel li {
|
||||||
margin: 5px;
|
|
||||||
padding: 10px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.LeftPanel li {
|
|
||||||
border-bottom: 1px #555 solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.LeftPanel li:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.LeftPanel li > * {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.LeftPanel div.description {
|
.LeftPanel div.description {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
|
@ -58,7 +42,3 @@ limitations under the License.
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.LeftPanel .description .last-message {
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -14,6 +15,39 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** contains styles for everything before the session view, like the session picker, login, load view, ... */
|
||||||
|
|
||||||
|
.SessionPickerView {
|
||||||
|
padding: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionPickerView ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionPickerView li {
|
||||||
|
margin: 0.4em 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionPickerView .sessionInfo {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionPickerView li span.userId {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionPickerView li span.error {
|
||||||
|
margin: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LoginView {
|
||||||
|
padding: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
.SessionLoadView {
|
.SessionLoadView {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -13,7 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
@import url('font.css');
|
||||||
@import url('layout.css');
|
@import url('layout.css');
|
||||||
@import url('login.css');
|
@import url('login.css');
|
||||||
@import url('left-panel.css');
|
@import url('left-panel.css');
|
||||||
|
@ -21,6 +22,8 @@ limitations under the License.
|
||||||
@import url('timeline.css');
|
@import url('timeline.css');
|
||||||
@import url('avatar.css');
|
@import url('avatar.css');
|
||||||
@import url('spinner.css');
|
@import url('spinner.css');
|
||||||
|
@import url('form.css');
|
||||||
|
@import url('status.css');
|
||||||
|
|
||||||
/* only if the body contains the whole app (e.g. we're not embedded in a page), make some changes */
|
/* only if the body contains the whole app (e.g. we're not embedded in a page), make some changes */
|
||||||
body.hydrogen {
|
body.hydrogen {
|
||||||
|
@ -32,10 +35,6 @@ body.hydrogen {
|
||||||
|
|
||||||
.hydrogen {
|
.hydrogen {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, sans-serif,
|
|
||||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
||||||
background-color: black;
|
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hiddenWithLayout {
|
.hiddenWithLayout {
|
||||||
|
@ -45,78 +44,3 @@ body.hydrogen {
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.SessionStatusView {
|
|
||||||
display: flex;
|
|
||||||
padding: 5px;
|
|
||||||
background-color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionStatusView p {
|
|
||||||
margin: 0 10px;
|
|
||||||
word-break: break-all;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionStatusView button {
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
color: currentcolor;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.RoomPlaceholderView {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionPickerView {
|
|
||||||
padding: 0.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionPickerView ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionPickerView li {
|
|
||||||
margin: 0.4em 0;
|
|
||||||
font-size: 1.2em;
|
|
||||||
background-color: grey;
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionPickerView .sessionInfo {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionPickerView li span.userId {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SessionPickerView li span.error {
|
|
||||||
margin: 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.LoginView {
|
|
||||||
padding: 0.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form > div {
|
|
||||||
margin: 0.4em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form input {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -14,10 +15,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
.RoomPlaceholderView {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
.RoomHeader {
|
.RoomHeader {
|
||||||
padding: 10px;
|
align-items: center;
|
||||||
background-color: #333;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.RoomHeader > *:last-child {
|
.RoomHeader > *:last-child {
|
||||||
|
@ -30,16 +34,7 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.RoomHeader button {
|
.RoomHeader button {
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
display: none;
|
|
||||||
font-size: 1.5em;
|
|
||||||
padding: 0;
|
|
||||||
display: block;
|
display: block;
|
||||||
background: white;
|
|
||||||
border: none;
|
|
||||||
font-weight: bolder;
|
|
||||||
line-height: 40px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.RoomHeader .back {
|
.RoomHeader .back {
|
||||||
|
@ -52,24 +47,11 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.RoomHeader .topic {
|
.RoomHeader .topic {
|
||||||
font-size: 0.8em;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back::before {
|
|
||||||
content: "☰";
|
|
||||||
}
|
|
||||||
|
|
||||||
.more::before {
|
|
||||||
content: "⋮";
|
|
||||||
}
|
|
||||||
|
|
||||||
.RoomHeader {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.RoomHeader .description {
|
.RoomHeader .description {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
@ -82,14 +64,8 @@ limitations under the License.
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.RoomView_error {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.MessageComposer > input {
|
.MessageComposer > input {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 0.8em;
|
|
||||||
border: none;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -37,6 +38,12 @@ limitations under the License.
|
||||||
animation-duration: 2s;
|
animation-duration: 2s;
|
||||||
animation-iteration-count: infinite;
|
animation-iteration-count: infinite;
|
||||||
animation-timing-function: linear;
|
animation-timing-function: linear;
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
* see if with IE11 we can just set a static stroke state and make it rotate?
|
||||||
|
*/
|
||||||
|
stroke-dasharray: 0 0 10 90;
|
||||||
|
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: currentcolor;
|
stroke: currentcolor;
|
||||||
stroke-width: 12;
|
stroke-width: 12;
|
||||||
|
|
33
src/ui/web/css/status.css
Normal file
33
src/ui/web/css/status.css
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.SessionStatusView {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionStatusView p {
|
||||||
|
margin: 0 10px;
|
||||||
|
word-break: break-all;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionStatusView button {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
color: currentcolor;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
7
src/ui/web/css/themes/README.md
Normal file
7
src/ui/web/css/themes/README.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
things that go in the theme:
|
||||||
|
- margin specialization
|
||||||
|
- padding
|
||||||
|
- colors (foreground, background, border, ...)
|
||||||
|
- border-radius
|
||||||
|
- font faces, weights and sizes
|
||||||
|
- alignment
|
186
src/ui/web/css/themes/bubbles/theme.css
Normal file
186
src/ui/web/css/themes/bubbles/theme.css
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hydrogen {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, sans-serif, 'emoji';
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
border-radius: 100%;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel {
|
||||||
|
background: #333;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel li {
|
||||||
|
margin: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
/* vertical align */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel li {
|
||||||
|
border-bottom: 1px #555 solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel li:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel li > * {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel .description .last-message {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.SessionStatusView {
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomPlaceholderView {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionPickerView li {
|
||||||
|
font-size: 1.2em;
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.RoomHeader {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomHeader button {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 1.5em;
|
||||||
|
padding: 0;
|
||||||
|
background: white;
|
||||||
|
border: none;
|
||||||
|
font-weight: bolder;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back::before {
|
||||||
|
content: "☰";
|
||||||
|
}
|
||||||
|
|
||||||
|
.more::before {
|
||||||
|
content: "⋮";
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomHeader .topic {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomHeader {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomView_error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MessageComposer > input {
|
||||||
|
padding: 0.8em;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container {
|
||||||
|
max-width: 80%;
|
||||||
|
padding: 5px 10px;
|
||||||
|
margin: 5px 10px;
|
||||||
|
background: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container .sender {
|
||||||
|
margin: 5px 0;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextMessageView .message-container time {
|
||||||
|
padding: 2px 0 0px 20px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container time {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.own time {
|
||||||
|
color: lightgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.own .message-container {
|
||||||
|
background-color: darkgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextMessageView.own .message-container {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextMessageView.pending .message-container {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextMessageView .message-container time {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container p {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.AnnouncementView {
|
||||||
|
margin: 5px 0;
|
||||||
|
padding: 5px 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.AnnouncementView > div {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #333;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #CCC;
|
||||||
|
text-align: center;
|
||||||
|
}
|
152
src/ui/web/css/themes/element/inter.css
Normal file
152
src/ui/web/css/themes/element/inter.css
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-Thin.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-Thin.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-ThinItalic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-ThinItalic.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-ExtraLight.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-ExtraLight.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-ExtraLightItalic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-ExtraLightItalic.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-Light.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-Light.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-LightItalic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-LightItalic.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-Regular.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-Regular.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-Italic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-Italic.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-Medium.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-Medium.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-MediumItalic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-MediumItalic.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-SemiBold.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-SemiBold.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-SemiBoldItalic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-SemiBoldItalic.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-Bold.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-Bold.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-BoldItalic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-BoldItalic.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-ExtraBold.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-ExtraBold.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-ExtraBoldItalic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-ExtraBoldItalic.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-Black.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-Black.woff?v=3.13") format("woff");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("inter/Inter-BlackItalic.woff2?v=3.13") format("woff2"),
|
||||||
|
url("inter/Inter-BlackItalic.woff?v=3.13") format("woff");
|
||||||
|
}
|
BIN
src/ui/web/css/themes/element/inter/Inter-Black.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Black.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Black.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Black.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-BlackItalic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-BlackItalic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-BlackItalic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-BlackItalic.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Bold.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Bold.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Bold.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Bold.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-BoldItalic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-BoldItalic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-BoldItalic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraBold.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraBold.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraBold.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraBold.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraBoldItalic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraBoldItalic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraBoldItalic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraBoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraLight.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraLight.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraLight.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraLight.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraLightItalic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraLightItalic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraLightItalic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ExtraLightItalic.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Italic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Italic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Italic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Italic.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Light.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Light.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Light.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Light.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-LightItalic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-LightItalic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-LightItalic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-LightItalic.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Medium.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Medium.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Medium.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Medium.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-MediumItalic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-MediumItalic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-MediumItalic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-MediumItalic.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Regular.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Regular.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Regular.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Regular.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-SemiBold.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-SemiBold.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-SemiBold.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-SemiBold.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-SemiBoldItalic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-SemiBoldItalic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-SemiBoldItalic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-SemiBoldItalic.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Thin.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Thin.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-Thin.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-Thin.woff2
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ThinItalic.woff
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ThinItalic.woff
Normal file
Binary file not shown.
BIN
src/ui/web/css/themes/element/inter/Inter-ThinItalic.woff2
Normal file
BIN
src/ui/web/css/themes/element/inter/Inter-ThinItalic.woff2
Normal file
Binary file not shown.
188
src/ui/web/css/themes/element/theme.css
Normal file
188
src/ui/web/css/themes/element/theme.css
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import url('inter.css');
|
||||||
|
|
||||||
|
.hydrogen {
|
||||||
|
font-family: 'Inter', sans-serif, 'emoji';
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
border-radius: 100%;
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel {
|
||||||
|
background: #333;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel li {
|
||||||
|
margin: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
/* vertical align */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel li {
|
||||||
|
border-bottom: 1px #555 solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel li:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel li > * {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.LeftPanel .description .last-message {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.SessionStatusView {
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomPlaceholderView {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SessionPickerView li {
|
||||||
|
font-size: 1.2em;
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.RoomHeader {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomHeader button {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 1.5em;
|
||||||
|
padding: 0;
|
||||||
|
background: white;
|
||||||
|
border: none;
|
||||||
|
font-weight: bolder;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back::before {
|
||||||
|
content: "☰";
|
||||||
|
}
|
||||||
|
|
||||||
|
.more::before {
|
||||||
|
content: "⋮";
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomHeader .topic {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomHeader {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RoomView_error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MessageComposer > input {
|
||||||
|
padding: 0.8em;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container {
|
||||||
|
max-width: 80%;
|
||||||
|
padding: 5px 10px;
|
||||||
|
margin: 5px 10px;
|
||||||
|
background: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container .sender {
|
||||||
|
margin: 5px 0;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextMessageView .message-container time {
|
||||||
|
padding: 2px 0 0px 20px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container time {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.own time {
|
||||||
|
color: lightgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.own .message-container {
|
||||||
|
background-color: darkgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextMessageView.own .message-container {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextMessageView.pending .message-container {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TextMessageView .message-container time {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-container p {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.AnnouncementView {
|
||||||
|
margin: 5px 0;
|
||||||
|
padding: 5px 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.AnnouncementView > div {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #333;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #CCC;
|
||||||
|
text-align: center;
|
||||||
|
}
|
|
@ -28,21 +28,11 @@ limitations under the License.
|
||||||
|
|
||||||
.message-container {
|
.message-container {
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
max-width: 80%;
|
|
||||||
padding: 5px 10px;
|
|
||||||
margin: 5px 10px;
|
|
||||||
background: blue;
|
|
||||||
/* first try break-all, then break-word, which isn't supported everywhere */
|
/* first try break-all, then break-word, which isn't supported everywhere */
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-container .sender {
|
|
||||||
margin: 5px 0;
|
|
||||||
font-size: 0.9em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-container img {
|
.message-container img {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -54,50 +44,7 @@ limitations under the License.
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TextMessageView.own .message-container {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.TextMessageView .message-container time {
|
|
||||||
float: right;
|
|
||||||
padding: 2px 0 0px 20px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: lightblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-container time {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: lightblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.own time {
|
|
||||||
color: lightgreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
.own .message-container {
|
|
||||||
background-color: darkgreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
.TextMessageView.pending .message-container {
|
|
||||||
background-color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-container p {
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.AnnouncementView {
|
.AnnouncementView {
|
||||||
margin: 5px 0;
|
|
||||||
padding: 5px 10%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.AnnouncementView > div {
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 10px 20px;
|
|
||||||
background-color: #333;
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #CCC;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" type="text/css" href="css/main.css">
|
<link rel="stylesheet" type="text/css" href="css/main.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/themes/bubbles/theme.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
@ -53,6 +54,7 @@
|
||||||
<script id="main" type="module">
|
<script id="main" type="module">
|
||||||
import {LoginView} from "./login/LoginView.js";
|
import {LoginView} from "./login/LoginView.js";
|
||||||
const view = new LoginView(vm({
|
const view = new LoginView(vm({
|
||||||
|
isBusy: true,
|
||||||
loadViewModel: vm({
|
loadViewModel: vm({
|
||||||
loadLabel: "Doing something important...",
|
loadLabel: "Doing something important...",
|
||||||
loading: true,
|
loading: true,
|
||||||
|
|
Loading…
Reference in a new issue