Skip to content
Snippets Groups Projects
Verified Commit 2535a7d8 authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

feat: Add Full Screen Component for Improved User Experience

- Added new HTML file `317.html` that serves as a demo for the full-screen component which enhances user interaction by taking over the entire screen.
- Created JavaScript module `317.mjs` to manage the new full-screen functionality.
- Introduced `full-screen.mjs` that encapsulates the core logic for full-screen toggling and interaction within the custom element.
- Included style files `full-screen.pcss` and `full-screen.mjs` to style the component, ensuring visibility and usability of full-screen controls.
- Integrated full screen controls into existing `camera-capture.mjs`, allowing users to toggle fullscreen mode conveniently while capturing.

These changes aim to provide a seamless full-screen experience, streamlining user engagement with multimedia components across our platform.
parent a4c3b422
Branches
Tags
No related merge requests found
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>new full screen component #317</title>
<script src="./317.mjs" type="module"></script>
</head>
<body>
<h1>new full screen component #317</h1>
<p></p>
<ul>
<li><a href="https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/317">Issue #317</a></li>
<li><a href="/">Back to overview</a></li>
</ul>
<main>
<div id="mdga">This is the monster <monster-full-screen style="position:absolute;top:10px" data-monster-option-selector="#mdga"></monster-full-screen>div that will be big!</div>
<div>
</div>
<!-- Write your code here -->
</main>
</body>
</html>
/**
* @file development/issues/open/317.mjs
* @url https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/317
* @description new full screen component
* @issue 317
*/
import "../../../source/components/style/property.pcss";
import "../../../source/components/style/link.pcss";
import "../../../source/components/style/color.pcss";
import "../../../source/components/style/theme.pcss";
import "../../../source/components/style/normalize.pcss";
import "../../../source/components/style/typography.pcss";
import "../../../source/components/layout/full-screen.mjs";
...@@ -27,6 +27,8 @@ import {addErrorAttribute} from "../../dom/error.mjs"; ...@@ -27,6 +27,8 @@ import {addErrorAttribute} from "../../dom/error.mjs";
import {Queue} from "../../types/queue.mjs"; import {Queue} from "../../types/queue.mjs";
import {fireCustomEvent} from "../../dom/events.mjs"; import {fireCustomEvent} from "../../dom/events.mjs";
import "../layout/full-screen.mjs";
export {CameraCapture}; export {CameraCapture};
/** /**
...@@ -458,6 +460,7 @@ function getTemplate() { ...@@ -458,6 +460,7 @@ function getTemplate() {
// language=HTML // language=HTML
return ` return `
<div data-monster-role="control" part="control"> <div data-monster-role="control" part="control">
<monster-full-screen part="full-screen" data-monster-role="full-screen" data-monster-option-selector="#stream"></monster-full-screen>
<monster-state data-monster-role="emptyHistoryState"> <monster-state data-monster-role="emptyHistoryState">
<svg slot="visual" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" <svg slot="visual" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="350" width="350"
...@@ -490,7 +493,8 @@ function getTemplate() { ...@@ -490,7 +493,8 @@ function getTemplate() {
</monster-state> </monster-state>
<video autoplay style="display:none"></video>
<video id="stream" autoplay style="display:none"></video>
<canvas style="display:none;"></canvas> <canvas style="display:none;"></canvas>
<div> <div>
<monster-button part="takePictureButton" style="display:none" <monster-button part="takePictureButton" style="display:none"
......
...@@ -19,6 +19,15 @@ ...@@ -19,6 +19,15 @@
border-width: var(--monster-border-width); border-width: var(--monster-border-width);
color: var(--monster-bg-color-primary-4); color: var(--monster-bg-color-primary-4);
position: relative;
}
[ data-monster-role="full-screen"] {
position:absolute;
top:10px;
right:10px;
z-index: 99999;
} }
.camera-not-supported-text { .camera-not-supported-text {
......
/**
* Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
* Node module: @schukai/monster
*
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
*
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
* For more information about purchasing a commercial license, please contact schukai GmbH.
*/
import {instanceSymbol} from "../../constants.mjs";
import {addAttributeToken} from "../../dom/attributes.mjs";
import {
ATTRIBUTE_ERRORMESSAGE,
ATTRIBUTE_ROLE,
} from "../../dom/constants.mjs";
import {CustomControl} from "../../dom/customcontrol.mjs";
import {CustomElement} from "../../dom/customelement.mjs";
import {
assembleMethodSymbol,
registerCustomElement,
} from "../../dom/customelement.mjs";
import {findTargetElementFromEvent} from "../../dom/events.mjs";
import {isFunction} from "../../types/is.mjs";
import {FullScreenStyleSheet} from "./stylesheet/full-screen.mjs";
import {fireCustomEvent} from "../../dom/events.mjs";
export {FullScreen};
/**
* @private
* @type {symbol}
*/
export const fullScreenControlElementSymbol = Symbol("fullScreenControlElement");
/**
* @private
* @type {symbol}
*/
export const fullScreenElementSymbol = Symbol("fullScreenElement");
/**
* @private
* @type {symbol}
*/
export const fullScreenExitElementSymbol = Symbol("fullScreenExitElement");
/**
* A FullScreen
*
* @fragments /fragments/components/layout/full-screen/
*
* @example /examples/components/layout/full-screen-simple
*
* @since 4.10.0
* @copyright schukai GmbH
* @summary A beautiful FullScreen that can make your life easier and also looks good.
*/
class FullScreen extends CustomElement {
/**
* This method is called by the `instanceof` operator.
* @returns {symbol}
*/
static get [instanceSymbol]() {
return Symbol.for("@schukai/monster/components/layout/full-screen@@instance");
}
/**
*
* @return {Components.Layout.FullScreen
*/
[assembleMethodSymbol]() {
super[assembleMethodSymbol]();
initControlReferences.call(this);
initEventHandler.call(this);
return this;
}
/**
* To set the options via the HTML Tag, the attribute `data-monster-options` must be used.
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
*
* The individual configuration values can be found in the table.
*
* @property {Object} templates Template definitions
* @property {string} templates.main Main template
* @property {string} selector Selector for the control
*/
get defaults() {
return Object.assign({}, super.defaults, {
templates: {
main: getTemplate(),
},
selector: ":first-child"
});
}
/**
* @return {string}
*/
static getTag() {
return "monster-full-screen";
}
/**
* @return {CSSStyleSheet[]}
*/
static getCSSStyleSheet() {
return [FullScreenStyleSheet];
}
}
/**
* @private
* @return {initEventHandler}
*/
function initEventHandler() {
const self = this;
const element = this[fullScreenControlElementSymbol];
document.addEventListener('fullscreenchange', (event) => {
const control = findTargetControl.call(self);
if (document.fullscreenElement === control) {
self[fullScreenElementSymbol].classList.add("hidden");
self[fullScreenExitElementSymbol].classList.remove("hidden");
} else {
self[fullScreenExitElementSymbol].classList.add("hidden");
self[fullScreenElementSymbol].classList.remove("hidden");
}
});
const type = "click";
element.addEventListener(type, function (event) {
const control = findTargetControl.call(self);
if(!control) {
debugger
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, "No control found");
return;
}
fireCustomEvent(self, "monster-full-screen-clicked", {
element: control,
});
toggleFullscreen.call(self, control);
});
return this;
}
/**
* @private
* @return {void}
*/
function initControlReferences() {
this[fullScreenControlElementSymbol] = this.shadowRoot.querySelector(
`[${ATTRIBUTE_ROLE}="control"]`,
);
this[fullScreenElementSymbol] = this.shadowRoot.querySelector(
`[${ATTRIBUTE_ROLE}="fullscreen"]`,
);
this[fullScreenExitElementSymbol] = this.shadowRoot.querySelector(
`[${ATTRIBUTE_ROLE}="fullscreen-exit"]`,
);
}
/**
* @private
* @param self
* @returns {*}
*/
function findTargetControl(self) {
const rootNode = this.getRootNode?.() ?? document;
const selector = this.getOption("selector");
return rootNode.querySelector(selector);
}
/**
* @private
* @param element
*/
function toggleFullscreen(element) {
if (!document.fullscreenElement) {
element.requestFullscreen().catch(err => {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, err.message);
});
} else {
document.exitFullscreen();
}
}
/**
* @private
* @return {string}
*/
function getTemplate() {
// language=HTML
return `
<div data-monster-role="control" part="control">
<div data-monster-role="fullscreen">
<svg part="fullscreen" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
viewBox="0 0 16 16">
<path fill-rule="evenodd"
d="M5.828 10.172a.5.5 0 0 0-.707 0l-4.096 4.096V11.5a.5.5 0 0 0-1 0v3.975a.5.5 0 0 0 .5.5H4.5a.5.5 0 0 0 0-1H1.732l4.096-4.096a.5.5 0 0 0 0-.707m4.344 0a.5.5 0 0 1 .707 0l4.096 4.096V11.5a.5.5 0 1 1 1 0v3.975a.5.5 0 0 1-.5.5H11.5a.5.5 0 0 1 0-1h2.768l-4.096-4.096a.5.5 0 0 1 0-.707m0-4.344a.5.5 0 0 0 .707 0l4.096-4.096V4.5a.5.5 0 1 0 1 0V.525a.5.5 0 0 0-.5-.5H11.5a.5.5 0 0 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 0 .707m-4.344 0a.5.5 0 0 1-.707 0L1.025 1.732V4.5a.5.5 0 0 1-1 0V.525a.5.5 0 0 1 .5-.5H4.5a.5.5 0 0 1 0 1H1.732l4.096 4.096a.5.5 0 0 1 0 .707"/>
</svg>
</div>
<div data-monster-role="fullscreen-exit" class="hidden">
<svg part="fullscreen-exit" xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" viewBox="0 0 16 16">
<path d="M5.5 0a.5.5 0 0 1 .5.5v4A1.5 1.5 0 0 1 4.5 6h-4a.5.5 0 0 1 0-1h4a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 1 .5-.5m5 0a.5.5 0 0 1 .5.5v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 1 0 1h-4A1.5 1.5 0 0 1 10 4.5v-4a.5.5 0 0 1 .5-.5M0 10.5a.5.5 0 0 1 .5-.5h4A1.5 1.5 0 0 1 6 11.5v4a.5.5 0 0 1-1 0v-4a.5.5 0 0 0-.5-.5h-4a.5.5 0 0 1-.5-.5m10 1a1.5 1.5 0 0 1 1.5-1.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 0-.5.5v4a.5.5 0 0 1-1 0z"/>
</svg>
</div>
</div>`;
}
registerCustomElement(FullScreen);
[data-monster-role="control"] {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin: 0;
padding: 0.5rem;
height: 2rem;
width: 2rem;
border: 1px solid var(--monster-bg-color-primary-4);
border-radius: 2rem;
overflow: hidden;
color: var(--monster-color-primary-1);
background-color: var(--monster-bg-color-primary-1);
cursor: pointer;
}
[data-monster-role="fullscreen"] {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
[data-monster-role="fullscreen-exit"] {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.hidden {
display: none;
}
\ No newline at end of file
/**
* Copyright © schukai GmbH and all contributing authors, 2025. All rights reserved.
* Node module: @schukai/monster
*
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
*
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
* For more information about purchasing a commercial license, please contact schukai GmbH.
*/
import {addAttributeToken} from "../../../dom/attributes.mjs";
import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs";
export {FullScreenStyleSheet}
/**
* @private
* @type {CSSStyleSheet}
*/
const FullScreenStyleSheet = new CSSStyleSheet();
try {
FullScreenStyleSheet.insertRule(`
@layer fullscreen {
[data-monster-role=control]{align-items:center;background-color:var(--monster-bg-color-primary-1);border:1px solid var(--monster-bg-color-primary-4);border-radius:2rem;color:var(--monster-color-primary-1);cursor:pointer;display:flex;flex-direction:column;height:2rem;justify-content:center;margin:0;overflow:hidden;padding:.5rem;position:relative;width:2rem}[data-monster-role=fullscreen-exit],[data-monster-role=fullscreen]{align-items:center;display:flex;height:100%;justify-content:center;left:0;position:absolute;top:0;width:100%}.hidden{display:none}
}`, 0);
} catch (e) {
addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + "");
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment