Awful frontend for "temporary widgets"

t3chguy/demo/widgets2020
Travis Ralston 2020-09-21 14:39:15 -06:00
parent 76463e836e
commit eb9a29cec5
7 changed files with 326 additions and 1 deletions

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dummy Widget</title>
</head>
<body>
<button id="demoBtn">Click me to show a temp widget</button>
<p>This isn't using the neat theme stuff over the widget API</p>
<p id="answer"><!-- populated with js --></p>
</body>
</html>

View File

@ -0,0 +1,50 @@
/*
Copyright 2020 New Vector Ltd.
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.
*/
// TODO: Match the user's theme: https://github.com/vector-im/riot-web/issues/12794
@font-face {
font-family: 'Nunito';
font-style: normal;
font-weight: 400;
src: url('~matrix-react-sdk/res/fonts/Nunito/Nunito-Regular.ttf') format('truetype');
}
body {
font-family: Nunito, Arial, Helvetica, sans-serif;
background-color: #181b21;
color: #edf3ff;
}
body, html {
padding: 0;
margin: 0;
text-align: center;
padding-top: 30px;
}
button {
// A mix of AccessibleButton styles
cursor: pointer;
padding: 7px 18px;
text-align: center;
border-radius: 4px;
display: inline-block;
font-size: 14px;
color: #ffffff;
background-color: #03b381;
border: 0;
}

View File

@ -0,0 +1,54 @@
/*
Copyright 2020 New Vector Ltd.
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.
*/
// We have to trick webpack into loading our CSS for us.
require("./index.scss");
import * as qs from 'querystring';
import { Capability, KnownWidgetActions, WidgetApi } from 'matrix-react-sdk/src/widgets/WidgetApi';
let widgetApi: WidgetApi;
(async function() {
try {
// The widget's options are encoded into the fragment to avoid leaking info to the server. The widget
// spec on the other hand requires the widgetId and parentUrl to show up in the regular query string.
const widgetQuery = qs.parse(window.location.hash.substring(1));
const query = Object.assign({}, qs.parse(window.location.search.substring(1)), widgetQuery);
const qsParam = (name: string, optional = false): string => {
if (!optional && (!query[name] || typeof (query[name]) !== 'string')) {
throw new Error(`Expected singular ${name} in query string`);
}
return <string>query[name];
};
// Set this up as early as possible because Element will be hitting it almost immediately.
widgetApi = new WidgetApi(qsParam('parentUrl'), qsParam('widgetId'), []);
widgetApi.on(KnownWidgetActions.ClosedWidgetResponse, req => {
document.getElementById("answer").innerText = "RESPONSE FROM TEMP WIDGET: " + JSON.stringify(req.data);
});
document.getElementById("demoBtn").onclick = () => {
const url = new URL(window.location.href);
url.pathname = "/theme_widget.html";
url.search = "";
widgetApi.openTempWidget(url.toString(), {question: "Answer to everything?"});
};
} catch (e) {
console.error("Error setting up Jitsi widget", e);
document.getElementById("widgetActionContainer").innerText = "Failed to load Jitsi widget";
}
})();

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Theme Widget</title>
</head>
<body class="client-element-web">
<h1>Example Theme Widget</h1>
<div>
<h2>Button Decorations</h2>
<button type="button" class="primary">Primary</button>
<button type="button" class="danger">Danger</button>
<button type="button" class="cancel">Cancel</button>
</div>
<div>
<h2>Actual Dialog Controls (closes the dialog)</h2>
<button type="button" id="closeButton">Close</button>
</div>
<div>
<h2>Metadata</h2>
<p id="question"><!-- populated with js --></p>
<p id="theme"><!-- populated with js --></p>
</div>
</body>
</html>

View File

@ -0,0 +1,103 @@
/*
Copyright 2020 New Vector Ltd.
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.
*/
// TODO: Match the user's theme: https://github.com/vector-im/riot-web/issues/12794
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
unicode-range: U+0000-20e2,U+20e4-23ce,U+23d0-24c1,U+24c3-259f,U+25c2-2664,U+2666-2763,U+2765-2b05,U+2b07-2b1b,U+2b1d-10FFFF;
src: url("~matrix-react-sdk/res/fonts/Inter/Inter-Regular.woff2?v=3.13") format("woff2"),
url("~matrix-react-sdk/res/fonts/Inter/Inter-Regular.woff?v=3.13") format("woff");
}
body {
font-family: Inter, Arial, Helvetica, sans-serif;
}
body, html {
padding: 10px;
margin: 0;
}
body.client-element-web {
&.is-dark {
background-color: #181b21;
color: #edf3ff;
}
&:not(.is-dark) {
background-color: #edf3ff;
color: #181b21;
}
button {
cursor: pointer;
padding: 7px 18px;
text-align: center;
border-radius: 4px;
display: inline-block;
font-size: 14px;
color: #ffffff;
background-color: var(--accent-color, #03b381);
border: 0;
}
button.danger {
background-color: #ff4b55;
}
button.cancel {
background-color: transparent;
color: #03b381;
}
}
body.client-element-android {
&.is-dark {
background-color: #062600;
color: #c6ffc6;
}
&:not(.is-dark) {
background-color: #c6ffc6;
color: #181b21;
}
button {
cursor: pointer;
padding: 12px 24px;
text-align: center;
border-radius: 12px;
display: inline-block;
font-size: 15px;
font-weight: bold;
color: #ffffff;
background-color: var(--accent-color, #03b381);
border: 0;
}
button.danger {
background-color: #ff4b55;
}
button.cancel {
background-color: transparent;
color: var(--accent-color, #03b381);
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2020 New Vector Ltd.
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.
*/
// We have to trick webpack into loading our CSS for us.
require("./index.scss");
import * as qs from 'querystring';
import { KnownWidgetActions, WidgetApi } from 'matrix-react-sdk/src/widgets/WidgetApi';
let widgetApi: WidgetApi;
(async function() {
try {
// The widget's options are encoded into the fragment to avoid leaking info to the server. The widget
// spec on the other hand requires the widgetId and parentUrl to show up in the regular query string.
const widgetQuery = qs.parse(window.location.hash.substring(1));
const query = Object.assign({}, qs.parse(window.location.search.substring(1)), widgetQuery);
const qsParam = (name: string, optional = false): string => {
if (!optional && (!query[name] || typeof (query[name]) !== 'string')) {
throw new Error(`Expected singular ${name} in query string`);
}
return <string>query[name];
};
// Set this up as early as possible because Element will be hitting it almost immediately.
widgetApi = new WidgetApi(qsParam('parentUrl'), qsParam('widgetId'), []);
widgetApi.on(KnownWidgetActions.UpdateThemeInfo, (themeInfo) => {
console.log("Got theme info: ", themeInfo);
document.getElementById("theme").innerText = "THEME: " + JSON.stringify(themeInfo.data);
const clientName = themeInfo.data.clientName || "element-web";
const isDark = themeInfo.data.isDark || false;
const accentColour = themeInfo.data.accentColor || "#03b381";
document.body.className = `client-${clientName} ${isDark ? 'is-dark' : ''}`;
document.body.style.setProperty("--accent-color", accentColour);
});
widgetApi.on(KnownWidgetActions.SendWidgetConfig, (config) => {
console.log("Got widget config: ", config);
document.getElementById("question").innerText = "INIT PARAMS: " + JSON.stringify(config.data);
});
document.getElementById("closeButton").onclick = () => {
widgetApi.closeWidget({answer: 42});
};
} catch (e) {
console.error("Error setting up Jitsi widget", e);
document.getElementById("widgetActionContainer").innerText = "Failed to load Jitsi widget";
}
})();

View File

@ -39,6 +39,8 @@ module.exports = (env, argv) => {
"indexeddb-worker": "./src/vector/indexeddb-worker.js",
"mobileguide": "./src/vector/mobile_guide/index.js",
"jitsi": "./src/vector/jitsi/index.ts",
"theme_widget": "./src/vector/theme_widget/index.ts",
"dummy_widget": "./src/vector/dummy_widget/index.ts",
"usercontent": "./node_modules/matrix-react-sdk/src/usercontent/index.js",
// CSS themes
@ -312,7 +314,7 @@ module.exports = (env, argv) => {
// HtmlWebpackPlugin will screw up our formatting like the names
// of the themes and which chunks we actually care about.
inject: false,
excludeChunks: ['mobileguide', 'usercontent', 'jitsi'],
excludeChunks: ['mobileguide', 'usercontent', 'jitsi', 'theme_widget', 'dummy_widget'],
minify: argv.mode === 'production',
vars: {
og_image_url: og_image_url,
@ -327,6 +329,22 @@ module.exports = (env, argv) => {
chunks: ['jitsi'],
}),
// This is the theme_widget wrapper (embedded, so isolated stack)
new HtmlWebpackPlugin({
template: './src/vector/theme_widget/index.html',
filename: 'theme_widget.html',
minify: argv.mode === 'production',
chunks: ['theme_widget'],
}),
// This is the dummy_widget wrapper (embedded, so isolated stack)
new HtmlWebpackPlugin({
template: './src/vector/dummy_widget/index.html',
filename: 'dummy_widget.html',
minify: argv.mode === 'production',
chunks: ['dummy_widget'],
}),
// This is the mobile guide's entry point (separate for faster mobile loading)
new HtmlWebpackPlugin({
template: './src/vector/mobile_guide/index.html',