mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-10 09:39:58 +00:00
Move UI components to ui/ directory
This commit is contained in:
11
ext/src/ui/popup/index.html
Executable file
11
ext/src/ui/popup/index.html
Executable file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="styles/index.css">
|
||||
<script src="bundle.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
240
ext/src/ui/popup/index.tsx
Executable file
240
ext/src/ui/popup/index.tsx
Executable file
@@ -0,0 +1,240 @@
|
||||
/* tslint:disable:max-line-length */
|
||||
"use strict";
|
||||
|
||||
import React, { Component } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import { getNextEllipsis } from "../../lib/utils";
|
||||
import * as types from "../../types";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
// macOS styles
|
||||
browser.runtime.getPlatformInfo()
|
||||
.then(platformInfo => {
|
||||
if (platformInfo.os === "mac") {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = "styles/mac.css";
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const winWidth = 350;
|
||||
let winHeight = 200;
|
||||
|
||||
let frameHeight: number;
|
||||
let frameWidth: number;
|
||||
|
||||
|
||||
interface PopupAppState {
|
||||
receivers: types.Receiver[];
|
||||
selectedMedia: string;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
class PopupApp extends Component<{}, PopupAppState> {
|
||||
private port: browser.runtime.Port;
|
||||
private win: browser.windows.Window;
|
||||
|
||||
constructor (props: {}) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
receivers: []
|
||||
, selectedMedia: "app"
|
||||
, isLoading: false
|
||||
};
|
||||
|
||||
// Store window ref
|
||||
browser.windows.getCurrent().then(win => {
|
||||
this.win = win;
|
||||
frameHeight = win.height - window.innerHeight;
|
||||
frameWidth = win.width - window.innerWidth;
|
||||
});
|
||||
|
||||
this.onSelectChange = this.onSelectChange.bind(this);
|
||||
this.onCast = this.onCast.bind(this);
|
||||
}
|
||||
|
||||
public componentDidMount () {
|
||||
const backgroundPort = browser.runtime.connect({
|
||||
name: "popup"
|
||||
});
|
||||
|
||||
backgroundPort.onMessage.addListener((message: types.Message) => {
|
||||
if (message.subject === "popup:/assignShim") {
|
||||
this.setPort(message.data.tabId
|
||||
, message.data.frameId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public render () {
|
||||
const shareMedia =
|
||||
this.state.selectedMedia === "tab"
|
||||
|| this.state.selectedMedia === "screen";
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="media-select">
|
||||
Cast
|
||||
<select value={ this.state.selectedMedia }
|
||||
onChange={ this.onSelectChange }
|
||||
className="media-select-dropdown">
|
||||
<option value="app" disabled={ shareMedia }>this site's app</option>
|
||||
<option value="tab" disabled={ !shareMedia }>Tab</option>
|
||||
<option value="screen" disabled={ !shareMedia }>Screen</option>
|
||||
</select>
|
||||
to:
|
||||
</div>
|
||||
<ul className="receivers">
|
||||
{ this.state.receivers.map((receiver, i) => {
|
||||
return (
|
||||
<Receiver receiver={ receiver }
|
||||
onCast={ this.onCast }
|
||||
isLoading={ this.state.isLoading }
|
||||
key={ i }/>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private async setPort (shimTabId: number, shimFrameId: number) {
|
||||
if (this.port) {
|
||||
this.port.disconnect();
|
||||
}
|
||||
|
||||
this.port = browser.tabs.connect(shimTabId, {
|
||||
name: "popup"
|
||||
, frameId: shimFrameId
|
||||
});
|
||||
|
||||
this.port.postMessage({
|
||||
subject: "shim:/popupReady"
|
||||
});
|
||||
|
||||
this.port.onMessage.addListener((message: types.Message) => {
|
||||
switch (message.subject) {
|
||||
case "popup:/populateReceiverList": {
|
||||
this.setState({
|
||||
receivers: message.data.receivers
|
||||
, selectedMedia: message.data.selectedMedia
|
||||
}, () => {
|
||||
// Get height of content without window decoration
|
||||
winHeight = document.body.clientHeight + frameHeight;
|
||||
|
||||
// Adjust height to fit content
|
||||
browser.windows.update(this.win.id, {
|
||||
height: winHeight
|
||||
});
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "popup:/close": {
|
||||
window.close();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onCast (receiver: types.Receiver) {
|
||||
this.setState({
|
||||
isLoading: true
|
||||
});
|
||||
|
||||
this.port.postMessage({
|
||||
subject: "shim:/selectReceiver"
|
||||
, data: {
|
||||
receiver
|
||||
, selectedMedia: this.state.selectedMedia
|
||||
, a: 5
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onSelectChange (ev: React.ChangeEvent<HTMLSelectElement>) {
|
||||
this.setState({
|
||||
selectedMedia: ev.target.value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface ReceiverProps {
|
||||
receiver: types.Receiver;
|
||||
isLoading: boolean;
|
||||
onCast (receiver: types.Receiver): void;
|
||||
}
|
||||
|
||||
interface ReceiverState {
|
||||
ellipsis: string;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
class Receiver extends Component<ReceiverProps, ReceiverState> {
|
||||
constructor (props: ReceiverProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isLoading: false
|
||||
, ellipsis: ""
|
||||
};
|
||||
|
||||
this.handleCast = this.handleCast.bind(this);
|
||||
}
|
||||
|
||||
public render () {
|
||||
return (
|
||||
<li className="receiver">
|
||||
<div className="receiver-name">
|
||||
{ this.props.receiver.friendlyName }
|
||||
</div>
|
||||
<div className="receiver-address">
|
||||
{ `${this.props.receiver.address}:${this.props.receiver.port}` }
|
||||
</div>
|
||||
<div className="receiver-status">
|
||||
{ this.props.receiver.currentApp &&
|
||||
`- ${this.props.receiver.currentApp}` }
|
||||
</div>
|
||||
<button className="receiver-connect"
|
||||
onClick={ this.handleCast }
|
||||
disabled={this.props.isLoading}>
|
||||
{ this.state.isLoading
|
||||
? _("popupCastingButtonLabel") +
|
||||
(this.state.isLoading
|
||||
? this.state.ellipsis
|
||||
: "")
|
||||
: _("popupCastButtonLabel") }
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
private handleCast () {
|
||||
this.props.onCast(this.props.receiver);
|
||||
|
||||
this.setState({
|
||||
isLoading: true
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
this.setState(state => ({
|
||||
ellipsis: getNextEllipsis(state.ellipsis)
|
||||
}));
|
||||
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ReactDOM.render(
|
||||
<PopupApp />
|
||||
, document.querySelector("#root"));
|
||||
68
ext/src/ui/popup/styles/index.css
Executable file
68
ext/src/ui/popup/styles/index.css
Executable file
@@ -0,0 +1,68 @@
|
||||
body {
|
||||
background: -moz-dialog;
|
||||
color: -moz-dialogtext;
|
||||
margin: initial;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
.media-select {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
|
||||
margin: 0 1em;
|
||||
padding: 0.75em 0;
|
||||
}
|
||||
|
||||
.media-select-dropdown {
|
||||
display: inline-block;
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
.receivers {
|
||||
list-style: none;
|
||||
margin: initial;
|
||||
padding: initial;
|
||||
}
|
||||
.receiver {
|
||||
column-gap: 0.75em;
|
||||
display: grid;
|
||||
flex-direction: column;
|
||||
grid-template-columns: min-content 1fr min-content;
|
||||
grid-template-rows: min-content min-content 1fr;
|
||||
grid-template-areas:
|
||||
"name name connect"
|
||||
"address status connect";
|
||||
justify-content: center;
|
||||
margin: 0 1em;
|
||||
padding: 0.75em 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.receiver:not(:last-child) {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.receiver-name,
|
||||
.receiver-address {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.receiver-name {
|
||||
font-size: 1.1em;
|
||||
grid-area: name;
|
||||
}
|
||||
.receiver-address {
|
||||
color: GrayText;
|
||||
grid-area: address;
|
||||
}
|
||||
.receiver-status {
|
||||
grid-area: status;
|
||||
}
|
||||
.receiver-connect {
|
||||
align-self: center;
|
||||
grid-area: connect;
|
||||
justify-self: end;
|
||||
min-width: 100px;
|
||||
height: 32px;
|
||||
}
|
||||
22
ext/src/ui/popup/styles/mac.css
Executable file
22
ext/src/ui/popup/styles/mac.css
Executable file
@@ -0,0 +1,22 @@
|
||||
body {
|
||||
background: rgb(236, 236, 236);
|
||||
font: menu;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
button:not([disabled]):hover:active {
|
||||
color: -moz-mac-buttonactivetext;
|
||||
}
|
||||
|
||||
.receiver-address,
|
||||
.receiver-status {
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
.receiver-connect {
|
||||
height: 22px;
|
||||
}
|
||||
Reference in New Issue
Block a user