Compare commits

...
Sign in to create a new pull request.

10 commits

Author SHA1 Message Date
Michael Telatynski
55e6ff9b2d Merge branch 't3chguy/feat/widgets' of github.com:vector-im/riot-web into t3chguy/demo/widgets2020 2020-10-19 19:38:25 +01:00
Michael Telatynski
c75a4add42 Merge branch 'develop' of github.com:vector-im/riot-web into t3chguy/feat/widgets 2020-10-19 18:51:22 +01:00
Michael Telatynski
4d8fe1f7f3 Jitsi accept theme variable and restyle
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-10-19 18:51:16 +01:00
Michael Telatynski
22e3286b96 fix
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-10-14 10:26:50 +01:00
Michael Telatynski
97b3a4a3e0 Merge branch 'develop' of github.com:vector-im/riot-web into t3chguy/feat/widgets 2020-10-13 13:46:56 +01:00
Michael Telatynski
b66ab3991b Update sample widgets with new matrix-widget-api interfaces
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-10-08 15:24:07 +01:00
Michael Telatynski
2ed497bcf6 Merge branch 't3chguy/demo/widgets2020' of github.com:vector-im/riot-web into t3chguy/feat/widgets 2020-10-08 13:10:14 +01:00
Michael Telatynski
b12936447f Merge branch 'develop' of github.com:vector-im/riot-web into t3chguy/demo/widgets2020 2020-09-28 14:39:52 +01:00
Michael Telatynski
66bd562c21 stash tweaks to the test widgets
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-09-28 12:28:59 +01:00
Travis Ralston
eb9a29cec5 Awful frontend for "temporary widgets" 2020-09-21 14:39:15 -06:00
9 changed files with 358 additions and 5 deletions

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dummy Widget</title>
</head>
<body>
<button id="demoBtn">Click me to show a modal widget</button>
<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,61 @@
/*
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 {ModalButtonKind, WidgetApi, WidgetApiToWidgetAction} from 'matrix-widget-api';
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.
const parentOrigin = new URL(qsParam('parentUrl')).origin;
widgetApi = new WidgetApi(qsParam("widgetId"), parentOrigin);
widgetApi.addEventListener(WidgetApiToWidgetAction.CloseModalWidget, (req: CustomEvent) => {
document.getElementById("answer").innerText = "Response from Modal: " + JSON.stringify(req.detail);
});
widgetApi.start();
document.getElementById("demoBtn").onclick = () => {
const url = new URL(window.location.href);
url.pathname = url.pathname.substr(0, url.pathname.lastIndexOf("/")) + "/theme_widget.html";
url.search = "";
widgetApi.openModalWidget(url.toString(), "Test Modal Widget", [
{id: "m.close", kind: ModalButtonKind.Danger, label: "Danger"},
{id: "org.secondary", kind: ModalButtonKind.Secondary, label: "Secondary"},
{id: "org.primary", kind: ModalButtonKind.Primary, label: "Primary"},
], {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

@ -23,11 +23,19 @@ limitations under the License.
src: url('~matrix-react-sdk/res/fonts/Nunito/Nunito-Regular.ttf') format('truetype');
}
$fg-color: #edf3ff;
$dark-fg: #edf3ff;
$dark-bg: rgba(141, 151, 165, 0.2);
$light-fg: #2e2f32;
$light-bg: #fff;
body {
font-family: Nunito, Arial, Helvetica, sans-serif;
background-color: #181b21;
color: $fg-color;
background-color: $dark-bg;
color: $dark-fg;
}
body.theme-light {
background-color: $light-bg;
color: $light-fg;
}
body, html {
@ -82,7 +90,7 @@ body, html {
&::before {
content: '';
background-size: contain;
background-color: $fg-color;
background-color: $dark-fg;
mask-repeat: no-repeat;
mask-position: center;
mask-image: url("~matrix-react-sdk/res/img/element-icons/call/video-call.svg");
@ -93,3 +101,7 @@ body, html {
margin: 0 auto; // center
}
}
body.theme-light .icon::before {
background-color: $light-fg;
}

View file

@ -67,6 +67,11 @@ let meetApi: any; // JitsiMeetExternalAPI
// out into a browser.
const parentUrl = qsParam('parentUrl', true);
const widgetId = qsParam('widgetId', true);
const theme = qsParam('theme', true);
if (theme) {
document.body.classList.add(`theme-${theme}`);
}
// Set this up as early as possible because Element will be hitting it almost immediately.
let readyPromise: Promise<[void, void]>;

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="button"><!-- 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,68 @@
/*
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 {WidgetApi, WidgetApiToWidgetAction, IWidgetApiRequest} from 'matrix-widget-api';
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.
const parentOrigin = new URL(qsParam('parentUrl')).origin;
widgetApi = new WidgetApi(qsParam("widgetId"), parentOrigin);
widgetApi.addEventListener(
`action:${WidgetApiToWidgetAction.ButtonClicked}`,
(ev: CustomEvent<IWidgetApiRequest>) => {
console.log("@@ clickety", ev.detail);
document.getElementById("button").innerText = "BUTTON CLICKED: " + JSON.stringify(ev.detail.data);
setTimeout(() => {
widgetApi.closeModalWidget(ev.detail.data);
}, 3000);
},
);
widgetApi.addEventListener(
`action:${WidgetApiToWidgetAction.WidgetConfig}`,
(ev: CustomEvent<IWidgetApiRequest>) => {
console.log("Got widget config: ", ev.detail.data);
document.getElementById("question").innerText = "INIT PARAMS: " + JSON.stringify(ev.detail.data);
},
);
widgetApi.start();
document.getElementById("closeButton").onclick = () => {
widgetApi.closeModalWidget({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',