Compare commits
10 commits
develop
...
t3chguy/de
Author | SHA1 | Date | |
---|---|---|---|
|
55e6ff9b2d | ||
|
c75a4add42 | ||
|
4d8fe1f7f3 | ||
|
22e3286b96 | ||
|
97b3a4a3e0 | ||
|
b66ab3991b | ||
|
2ed497bcf6 | ||
|
b12936447f | ||
|
66bd562c21 | ||
|
eb9a29cec5 |
9 changed files with 358 additions and 5 deletions
11
src/vector/dummy_widget/index.html
Normal file
11
src/vector/dummy_widget/index.html
Normal 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>
|
50
src/vector/dummy_widget/index.scss
Normal file
50
src/vector/dummy_widget/index.scss
Normal 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;
|
||||
}
|
61
src/vector/dummy_widget/index.ts
Normal file
61
src/vector/dummy_widget/index.ts
Normal 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";
|
||||
}
|
||||
})();
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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]>;
|
||||
|
|
25
src/vector/theme_widget/index.html
Normal file
25
src/vector/theme_widget/index.html
Normal 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>
|
103
src/vector/theme_widget/index.scss
Normal file
103
src/vector/theme_widget/index.scss
Normal 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);
|
||||
}
|
||||
}
|
68
src/vector/theme_widget/index.ts
Normal file
68
src/vector/theme_widget/index.ts
Normal 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";
|
||||
}
|
||||
})();
|
|
@ -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',
|
||||
|
|
Loading…
Add table
Reference in a new issue