diff --git a/src/vector/screenshots.html b/src/vector/screenshots.html new file mode 100644 index 0000000000..9f3bb5cbd2 --- /dev/null +++ b/src/vector/screenshots.html @@ -0,0 +1,106 @@ + + + + + + Element Screenshots + + + + + + + + + + + + + + + + + + + + + + <% for (var i=0; i < htmlWebpackPlugin.files.css.length; i++) { + var file = htmlWebpackPlugin.files.css[i]; + var match = file.match(/^bundles\/.*?\/theme-(.*)\.css$/); + if (match) { + var title = match[1].charAt(0).toUpperCase() + match[1].slice(1); + %> + + <% } else { %> + + <% } + } %> + + <% for (var i=0; i < htmlWebpackPlugin.tags.headTags.length; i++) { + var tag = htmlWebpackPlugin.tags.headTags[i]; + var path = tag.attributes && tag.attributes.href; + if (path.indexOf("Inter") !== -1) { %> + + <% } + } %> + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + diff --git a/src/vector/screenshots.tsx b/src/vector/screenshots.tsx new file mode 100644 index 0000000000..b72119ccee --- /dev/null +++ b/src/vector/screenshots.tsx @@ -0,0 +1,140 @@ +/* +Copyright 2022 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. +*/ + +// This file is a cut-down copy of index.ts. It goes together with +// screenshots.html to create a page allowing you to choose a component, +// Which is rendered with example data, allowing us to take screenshots +// (using code in matrix-react-sdk/tests/end-to-end-tests/screenshots.js) +// and compare for any changes against previous versions. + +import './modernizr'; +import * as ReactDOM from "react-dom"; +import React, { ChangeEvent, ReactElement } from 'react'; +import { MatrixClientPeg } from "matrix-react-sdk/src/MatrixClientPeg"; +import { screenshotNotificationUserSettingsTab } from './screenshots/notification_user_settings_tab'; + +let widthInput: HTMLInputElement; +let heightInput: HTMLInputElement; +let classInput: HTMLInputElement; + +async function settled(...promises: Array>) { + for (const prom of promises) { + try { + await prom; + } catch (e) { + console.error(e); + } + } +} + +async function start() { + const { + preparePlatform, + loadSkin, + loadLanguage, + loadTheme, + } = await import( + /* webpackChunkName: "init" */ + /* webpackPreload: true */ + "./init"); + + try { + preparePlatform(); + const loadLanguagePromise = loadLanguage(); + const loadThemePromise = loadTheme(); + const loadSkinPromise = loadSkin(); + await settled(loadSkinPromise, loadThemePromise, loadLanguagePromise); + + await loadSkinPromise; + await loadThemePromise; + await loadLanguagePromise; + + await myLoadApp(); + } catch (err) { + console.error(err); + } +} + +async function myLoadApp() { + // We know that MatrixClientPeg is a MatrixClientPegClass + await (MatrixClientPeg as any).createClient({}); + + window.matrixChat = ReactDOM.render( +
+ + + + +
+
, + document.getElementById('matrixchat'), + ); + + widthInput = document.getElementById("screenshot_width") as HTMLInputElement; + heightInput = document.getElementById("screenshot_height") as HTMLInputElement; + classInput = document.getElementById("screenshot_class") as HTMLInputElement; +} + +function selectChange(event: ChangeEvent) { + const screenshot = screenshots.find((scr) => scr.name === event.target.value); + if (screenshot) { + widthInput["value"] = screenshot.width.toString(); + heightInput["value"] = screenshot.height.toString(); + classInput["value"] = screenshot.cssClass; + ReactDOM.render( + screenshot.fn() as ReactElement, + document.getElementById('screenshot'), + ); + } +} + +/** + * To add more screenshots, add a row to this table. + * + * Note: width, height and cssClass act as hints to the screenshotting code in + * matrix-react-sdk about how to render the screenshot - they do not affect the + * size or appearance if you visit the page in your browser. + */ +const screenshots = [ + { + name: "NotificationUserSettingsTab_wide", + fn: screenshotNotificationUserSettingsTab, + width: 800, + height: 800, + cssClass: "mx_NotificationUserSettingsTab", + }, + { + name: "NotificationUserSettingsTab_narrow", + fn: screenshotNotificationUserSettingsTab, + width: 400, + height: 800, + cssClass: "mx_NotificationUserSettingsTab", + }, +]; + +start().catch(err => { + console.error(err); +}); diff --git a/src/vector/screenshots/notification_user_settings_tab.tsx b/src/vector/screenshots/notification_user_settings_tab.tsx new file mode 100644 index 0000000000..b4107818b1 --- /dev/null +++ b/src/vector/screenshots/notification_user_settings_tab.tsx @@ -0,0 +1,244 @@ +/* +Copyright 2022 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. +*/ + +import { IPushRules } from "matrix-js-sdk/src/@types/PushRules"; +import { MatrixClientPeg } from "matrix-react-sdk/src/MatrixClientPeg"; +import { PushProcessor } from 'matrix-js-sdk/src/pushprocessor'; +import React, { ReactElement } from 'react'; +import * as sdk from 'matrix-react-sdk'; + +export function screenshotNotificationUserSettingsTab(): ReactElement { + MatrixClientPeg.get().getPushRules = async () => { + return PushProcessor.rewriteDefaultRules(pushRulesJson() as IPushRules); + }; + + MatrixClientPeg.get().getPushers = async () => { + return { pushers: [] }; + }; + MatrixClientPeg.get().getThreePids = async () => { + return { threepids: [] }; + }; + + const NotificationUserSettingsTab= sdk.getComponent( + 'views.settings.tabs.user.NotificationUserSettingsTab'); + return ; +} + +function pushRulesJson() { + // This is a lightly-modified paste of the JSON returned from a GET + // to /pushrules/ + + /* eslint-disable */ + return { + "global": { + "underride": [ + { + "conditions": [ + { "kind": "event_match", "key": "type", "pattern": "m.call.invite" }, + ], + "actions": [ + "notify", + { "set_tweak": "sound", "value": "ring" }, + { "set_tweak": "highlight", "value": false }, + ], + "rule_id": ".m.rule.call", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "room_member_count", "is": "2" }, + { "kind": "event_match", "key": "type", "pattern": "m.room.message" }, + ], + "actions": [ + "notify", + { "set_tweak": "sound", "value": "default" }, + { "set_tweak": "highlight", "value": false }, + ], + "rule_id": ".m.rule.room_one_to_one", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "room_member_count", "is": "2" }, + { "kind": "event_match", "key": "type", "pattern": "m.room.encrypted" }, + ], + "actions": [ + "notify", + { "set_tweak": "sound", "value": "default" }, + { "set_tweak": "highlight", "value": false }, + ], + "rule_id": ".m.rule.encrypted_room_one_to_one", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "event_match", "key": "type", "pattern": "m.room.message" }, + ], + "actions": [ + "dont_notify", + ], + "rule_id": ".m.rule.message", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "event_match", "key": "type", "pattern": "m.room.encrypted" }, + ], + "actions": [ + "dont_notify", + ], + "rule_id": ".m.rule.encrypted", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "event_match", "key": "type", "pattern": "im.vector.modular.widgets" }, + { "kind": "event_match", "key": "content.type", "pattern": "jitsi" }, + { "kind": "event_match", "key": "state_key", "pattern": "*" }, + ], + "actions": [ + "notify", + { "set_tweak": "highlight", "value": false }, + ], + "rule_id": ".im.vector.jitsi", + "default": true, + "enabled": true, + }, + ], + "sender": [], + "room": [], + "content": [ + { + "actions": [ + "notify", + { "set_tweak": "sound", "value": "default" }, + { "set_tweak": "highlight" }, + ], + "pattern": "username", + "rule_id": ".m.rule.contains_user_name", + "default": true, + "enabled": true, + }, + ], + "override": [ + { + "conditions": [], + "actions": [ + "dont_notify" + ], + "rule_id": ".m.rule.master", + "default": true, + "enabled": false, + }, + { + "conditions": [ + { "kind": "event_match", "key": "content.msgtype", "pattern": "m.notice" } + ], + "actions": [ + "dont_notify", + ], + "rule_id": ".m.rule.suppress_notices", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "event_match", "key": "type", "pattern": "m.room.member" }, + { "kind": "event_match", "key": "content.membership", "pattern": "invite" }, + { "kind": "event_match", "key": "state_key", "pattern": "@username:example.com" } + ], + "actions": [ + "notify", + { "set_tweak": "sound", "value": "default" }, + { "set_tweak": "highlight", "value": false } + ], + "rule_id": ".m.rule.invite_for_me", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "event_match", "key": "type", "pattern": "m.room.member" } + ], + "actions": [ + "dont_notify", + ], + "rule_id": ".m.rule.member_event", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "contains_display_name" } + ], + "actions": [ + "notify", + { "set_tweak": "sound", "value": "default" }, + { "set_tweak": "highlight" } + ], + "rule_id": ".m.rule.contains_display_name", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "event_match", "key": "content.body", "pattern": "@room" }, + { "kind": "sender_notification_permission", "key": "room" } + ], + "actions": [ + "notify", + { "set_tweak": "highlight", "value": true } + ], + "rule_id": ".m.rule.roomnotif", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "event_match", "key": "type", "pattern": "m.room.tombstone" }, + { "kind": "event_match", "key": "state_key", "pattern": "" } + ], + "actions": [ + "notify", + { "set_tweak": "highlight", "value": true } + ], + "rule_id": ".m.rule.tombstone", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { "kind": "event_match", "key": "type", "pattern": "m.reaction" } + ], + "actions": [ + "dont_notify", + ], + "rule_id": ".m.rule.reaction", + "default": true, + "enabled": true, + } + ], + }, + "device": {}, + }; + /* eslint-enable */ +} + diff --git a/webpack.config.js b/webpack.config.js index 3aed2154c4..ed39ff4d0b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -99,6 +99,7 @@ module.exports = (env, argv) => { entry: { "bundle": "./src/vector/index.ts", + "screenshots": "./src/vector/screenshots.tsx", "mobileguide": "./src/vector/mobile_guide/index.ts", "jitsi": "./src/vector/jitsi/index.ts", "usercontent": "./node_modules/matrix-react-sdk/src/usercontent/index.ts", @@ -496,6 +497,22 @@ module.exports = (env, argv) => { }, }), + // This is our screenshots page for testing + new HtmlWebpackPlugin({ + template: './src/vector/screenshots.html', + filename: 'screenshots.html', + + // we inject the links ourselves via the template, because + // 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'], + minify: false, + templateParameters: { + og_image_url: ogImageUrl, + }, + }), + // This is the jitsi widget wrapper (embedded, so isolated stack) new HtmlWebpackPlugin({ template: './src/vector/jitsi/index.html',