mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Add receiver selector options + misc options page improvements
This commit is contained in:
@@ -11,6 +11,43 @@ issues if you're going to work on something to avoid duplication of effort.
|
||||
Submit an issue for new features before submitting a PR.
|
||||
|
||||
|
||||
## Compatibility Report
|
||||
## Compatibility Reports
|
||||
|
||||
Compatibility reports are always helpful. Use the "Compatibility Report" issue template. Ensure you have a working environment and that the site is in the whitelist (check options page).
|
||||
|
||||
|
||||
## Localizations
|
||||
|
||||
Missing strings:
|
||||
|
||||
* `es`
|
||||
* `optionsMediaSyncElementDescription`
|
||||
* `optionsReceiverSelectorCategoryName`
|
||||
* `optionsReceiverSelectorCategoryDescription`
|
||||
* `optionsReceiverSelectorType`
|
||||
* `optionsReceiverSelectorTypeBrowser`
|
||||
* `optionsReceiverSelectorTypeNative`
|
||||
* `optionsReceiverSelectorWaitForConnection`
|
||||
* `optionsReceiverSelectorWaitForConnectionDescription`
|
||||
* `optionsReceiverSelectorCloseIfFocusLost`
|
||||
* `optionsMirroringAppIdDescription`
|
||||
* `nl`
|
||||
* `popupMediaTypeApp`
|
||||
* `popupMediaTypeTab`
|
||||
* `popupMediaTypeScreen`
|
||||
* `popupMediaTypeFile`
|
||||
* `popupMediaSelectCastLabel`
|
||||
* `popupMediaSelectToLabel`
|
||||
* `contextAddToWhitelist`
|
||||
* `contextAddToWhitelistRecommended`
|
||||
* `contextAddToWhitelistAdvancedAdd`
|
||||
* `optionsMediaSyncElementDescription`
|
||||
* `optionsReceiverSelectorCategoryName`
|
||||
* `optionsReceiverSelectorCategoryDescription`
|
||||
* `optionsReceiverSelectorType`
|
||||
* `optionsReceiverSelectorTypeBrowser`
|
||||
* `optionsReceiverSelectorTypeNative`
|
||||
* `optionsReceiverSelectorWaitForConnection`
|
||||
* `optionsReceiverSelectorWaitForConnectionDescription`
|
||||
* `optionsReceiverSelectorCloseIfFocusLost`
|
||||
* `optionsMirroringAppIdDescription`
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true
|
||||
, "esModuleInterop": true
|
||||
"esModuleInterop": true
|
||||
, "module": "commonjs"
|
||||
, "noImplicitAny": true
|
||||
, "removeComments": true
|
||||
|
||||
@@ -193,6 +193,10 @@
|
||||
"message": "Sync receiver state with media element"
|
||||
, "description": "Media casting sync checkbox label."
|
||||
}
|
||||
, "optionsMediaSyncElementDescription": {
|
||||
"message": "Synchronize state (playback, volume, captions, etc...) between the media element and the receiver device."
|
||||
, "description": "Media casting sync option description."
|
||||
}
|
||||
, "optionsMediaStopOnUnload": {
|
||||
"message": "Stop receiver playback on page unload"
|
||||
, "description": "Media stop on unload checkbox label."
|
||||
@@ -215,6 +219,39 @@
|
||||
, "description": "HTTP server port input label."
|
||||
}
|
||||
|
||||
, "optionsReceiverSelectorCategoryName": {
|
||||
"message": "Receiver selector"
|
||||
, "description": "Options page receiver selector category title."
|
||||
}
|
||||
, "optionsReceiverSelectorCategoryDescription": {
|
||||
"message": "Receiver device selection interface."
|
||||
, "description": "Options page receiver selector category description."
|
||||
}
|
||||
, "optionsReceiverSelectorType": {
|
||||
"message": "Type:"
|
||||
, "description": "Receiver selector type option label."
|
||||
}
|
||||
, "optionsReceiverSelectorTypeBrowser": {
|
||||
"message": "Browser"
|
||||
, "description": "Receiver selector type browser radio option label."
|
||||
}
|
||||
, "optionsReceiverSelectorTypeNative": {
|
||||
"message": "Native"
|
||||
, "description": "Receiver selector type native radio option label."
|
||||
}
|
||||
, "optionsReceiverSelectorWaitForConnection": {
|
||||
"message": "Wait for connection"
|
||||
, "description": "Receiver selector wait for connection option checkbox label."
|
||||
}
|
||||
, "optionsReceiverSelectorWaitForConnectionDescription": {
|
||||
"message": "Keep receiver selector open until the session is established or connection fails."
|
||||
, "description": "Receiver selector wait for connection option description."
|
||||
}
|
||||
, "optionsReceiverSelectorCloseIfFocusLost": {
|
||||
"message": "Close after losing focus"
|
||||
, "description": "Receiver selector close if focus lost option checkbox label."
|
||||
}
|
||||
|
||||
, "optionsUserAgentWhitelistCategoryName": {
|
||||
"message": "User agent whitelist"
|
||||
, "description": "Options page whitelist category title."
|
||||
@@ -282,6 +319,10 @@
|
||||
"message": "Receiver app ID:"
|
||||
, "description": "Mirroring app ID input label."
|
||||
}
|
||||
, "optionsMirroringAppIdDescription": {
|
||||
"message": "App ID for a registered Chromecast receiver application. Advanced use only. Must be compatible with the default app (see GitHub repo)."
|
||||
, "description": "Mirroring app ID option description."
|
||||
}
|
||||
|
||||
, "optionsReset": {
|
||||
"message": "Restore Defaults"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import { ReceiverSelectorType } from "./receiver_selectors";
|
||||
|
||||
export interface Options {
|
||||
bridgeApplicationName: string;
|
||||
mediaEnabled: boolean;
|
||||
@@ -9,6 +11,12 @@ export interface Options {
|
||||
localMediaServerPort: number;
|
||||
mirroringEnabled: boolean;
|
||||
mirroringAppId: string;
|
||||
receiverSelectorType: ReceiverSelectorType;
|
||||
|
||||
// TODO: Implement
|
||||
receiverSelectorCloseIfFocusLost: boolean;
|
||||
receiverSelectorWaitForConnection: boolean;
|
||||
|
||||
userAgentWhitelistEnabled: boolean;
|
||||
userAgentWhitelist: string[];
|
||||
|
||||
@@ -24,6 +32,9 @@ const options: Options = {
|
||||
, localMediaServerPort: 9555
|
||||
, mirroringEnabled: false
|
||||
, mirroringAppId: MIRRORING_APP_ID
|
||||
, receiverSelectorType: ReceiverSelectorType.Popup
|
||||
, receiverSelectorCloseIfFocusLost: true
|
||||
, receiverSelectorWaitForConnection: false
|
||||
, userAgentWhitelistEnabled: true
|
||||
, userAgentWhitelist: [
|
||||
"https://www.netflix.com/*"
|
||||
|
||||
@@ -639,11 +639,8 @@ async function onConnectShim (port: browser.runtime.Port) {
|
||||
}
|
||||
|
||||
|
||||
const { os } = await browser.runtime.getPlatformInfo();
|
||||
|
||||
const receiverSelector = getReceiverSelector(os === "mac"
|
||||
? ReceiverSelectorType.NativeMac
|
||||
: ReceiverSelectorType.Popup);
|
||||
const receiverSelector = getReceiverSelector(
|
||||
await options.get("receiverSelectorType"));
|
||||
|
||||
|
||||
function onReceiverSelectorSelected (
|
||||
|
||||
@@ -47,27 +47,13 @@ export default class EditableList extends Component<
|
||||
public render () {
|
||||
return (
|
||||
<div className="editable-list">
|
||||
<div className="editable-list__view-actions">
|
||||
{ this.state.rawView &&
|
||||
<button className="editable-list__save-raw-button"
|
||||
onClick={ this.handleSaveRaw }
|
||||
type="button">
|
||||
{ _("optionsUserAgentWhitelistSaveRaw") }
|
||||
</button> }
|
||||
<button className="editable-list__view-button"
|
||||
onClick={ this.handleSwitchView }
|
||||
type="button">
|
||||
{ this.state.rawView
|
||||
? _("optionsUserAgentWhitelistBasicView")
|
||||
: _("optionsUserAgentWhitelistRawView") }
|
||||
</button>
|
||||
</div>
|
||||
<hr />
|
||||
{ this.state.rawView
|
||||
? (
|
||||
<textarea className="editable-list__raw-view"
|
||||
rows={ this.props.data.length}
|
||||
value={ this.state.rawViewValue}
|
||||
rows={ this.props.data.length > 10
|
||||
? this.props.data.length
|
||||
: 10 }
|
||||
value={ this.state.rawViewValue }
|
||||
onChange={ this.handleRawViewTextAreaChange }
|
||||
ref={ el => { this.rawViewTextArea = el; }}>
|
||||
</textarea>
|
||||
@@ -88,15 +74,30 @@ export default class EditableList extends Component<
|
||||
onEdit={ this.handleNewItemEdit }
|
||||
editing={ true } /> }
|
||||
|
||||
<div className="editable-list__item editable-list__item-actions">
|
||||
<button className="editable-list__add-button"
|
||||
onClick={ this.handleAddItem }
|
||||
type="button">
|
||||
{ _("optionsUserAgentWhitelistAddItem") }
|
||||
</button>
|
||||
</div>
|
||||
</ul>
|
||||
)}
|
||||
<hr />
|
||||
<div className="editable-list__view-actions">
|
||||
{ !this.state.rawView &&
|
||||
<button className="editable-list__add-button"
|
||||
onClick={ this.handleAddItem }
|
||||
type="button">
|
||||
{ _("optionsUserAgentWhitelistAddItem") }
|
||||
</button> }
|
||||
{ this.state.rawView &&
|
||||
<button className="editable-list__save-raw-button"
|
||||
onClick={ this.handleSaveRaw }
|
||||
type="button">
|
||||
{ _("optionsUserAgentWhitelistSaveRaw") }
|
||||
</button> }
|
||||
<button className="editable-list__view-button"
|
||||
onClick={ this.handleSwitchView }
|
||||
type="button">
|
||||
{ this.state.rawView
|
||||
? _("optionsUserAgentWhitelistBasicView")
|
||||
: _("optionsUserAgentWhitelistRawView") }
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import getBridgeInfo, { BridgeInfo } from "../../lib/getBridgeInfo";
|
||||
import options from "../../lib/options";
|
||||
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/utils";
|
||||
|
||||
import { ReceiverSelectorType } from "../../receiver_selectors";
|
||||
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
@@ -73,6 +75,9 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
this.handleWhitelistChange = this.handleWhitelistChange.bind(this);
|
||||
|
||||
this.handleReceiverSelectorTypeChange
|
||||
= this.handleReceiverSelectorTypeChange.bind(this);
|
||||
|
||||
this.getWhitelistItemPatternError
|
||||
= this.getWhitelistItemPatternError.bind(this);
|
||||
}
|
||||
@@ -117,58 +122,66 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
</p>
|
||||
|
||||
<label className="option option--inline">
|
||||
<input name="mediaEnabled"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.mediaEnabled }
|
||||
onChange={ this.handleInputChange } />
|
||||
<div className="option__control">
|
||||
<input name="mediaEnabled"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.mediaEnabled }
|
||||
onChange={ this.handleInputChange } />
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{ _("optionsMediaEnabled") }
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className="option option--inline">
|
||||
<input name="mediaSyncElement"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.mediaSyncElement }
|
||||
onChange={ this.handleInputChange } />
|
||||
<div className="option__control">
|
||||
<input name="mediaSyncElement"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.mediaSyncElement }
|
||||
onChange={ this.handleInputChange } />
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{ _("optionsMediaSyncElement") }
|
||||
</div>
|
||||
<div className="option__description">
|
||||
{ _("optionsMediaSyncElementDescription") }
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className="option option--inline">
|
||||
<input name="mediaStopOnUnload"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.mediaStopOnUnload }
|
||||
onChange={ this.handleInputChange } />
|
||||
<div className="option__control">
|
||||
<input name="mediaStopOnUnload"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.mediaStopOnUnload }
|
||||
onChange={ this.handleInputChange } />
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{ _("optionsMediaStopOnUnload") }
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<fieldset className="category"
|
||||
disabled={ !this.state.options.mediaEnabled }>
|
||||
<legend className="category__name">
|
||||
<h2>{ _("optionsLocalMediaCategoryName") }</h2>
|
||||
</legend>
|
||||
<p className="category__description">
|
||||
{ _("optionsLocalMediaCategoryDescription") }
|
||||
</p>
|
||||
<hr />
|
||||
|
||||
<label className="option option--inline">
|
||||
<label className="option option--inline">
|
||||
<div className="option__control">
|
||||
<input name="localMediaEnabled"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.localMediaEnabled }
|
||||
onChange={ this.handleInputChange } />
|
||||
<div className="option__label">
|
||||
{ _("optionsLocalMediaEnabled") }
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{ _("optionsLocalMediaEnabled") }
|
||||
</div>
|
||||
<div className="option__description">
|
||||
{ _("optionsLocalMediaCategoryDescription") }
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className="option">
|
||||
<div className="option__label">
|
||||
{ _("optionsLocalMediaServerPort") }
|
||||
</div>
|
||||
<label className="option">
|
||||
<div className="option__label">
|
||||
{ _("optionsLocalMediaServerPort") }
|
||||
</div>
|
||||
<div className="option__control">
|
||||
<input name="localMediaServerPort"
|
||||
type="number"
|
||||
required
|
||||
@@ -176,8 +189,8 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
max="65535"
|
||||
value={ this.state.options.localMediaServerPort }
|
||||
onChange={ this.handleInputChange } />
|
||||
</label>
|
||||
</fieldset>
|
||||
</div>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<fieldset className="category">
|
||||
@@ -189,10 +202,12 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
</p>
|
||||
|
||||
<label className="option option--inline">
|
||||
<input name="mirroringEnabled"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.mirroringEnabled }
|
||||
onChange={ this.handleInputChange } />
|
||||
<div className="option__control">
|
||||
<input name="mirroringEnabled"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.mirroringEnabled }
|
||||
onChange={ this.handleInputChange } />
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{ _("optionsMirroringEnabled") }
|
||||
</div>
|
||||
@@ -202,11 +217,71 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
<div className="option__label">
|
||||
{ _("optionsMirroringAppId") }
|
||||
</div>
|
||||
<input name="mirroringAppId"
|
||||
type="text"
|
||||
required
|
||||
value={ this.state.options.mirroringAppId }
|
||||
onChange={ this.handleInputChange } />
|
||||
<div className="option__control">
|
||||
<input name="mirroringAppId"
|
||||
type="text"
|
||||
required
|
||||
value={ this.state.options.mirroringAppId }
|
||||
onChange={ this.handleInputChange } />
|
||||
<div className="option__description">
|
||||
{ _("optionsMirroringAppIdDescription") }
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<fieldset className="category">
|
||||
<legend className="category__name">
|
||||
<h2>{ _("optionsReceiverSelectorCategoryName") }</h2>
|
||||
</legend>
|
||||
<p className="category__description">
|
||||
{ _("optionsReceiverSelectorCategoryDescription") }
|
||||
</p>
|
||||
|
||||
{ this.state.platform === "mac" &&
|
||||
<label className="option">
|
||||
<div className="option__label">
|
||||
{ _("optionsReceiverSelectorType") }
|
||||
</div>
|
||||
<div className="option__control">
|
||||
<select name="receiverSelectorType"
|
||||
value={ this.state.options.receiverSelectorType }
|
||||
onChange={ this.handleReceiverSelectorTypeChange }>
|
||||
<option value={ ReceiverSelectorType.Popup }>
|
||||
{ _("optionsReceiverSelectorTypeBrowser") }
|
||||
</option>
|
||||
<option value={ ReceiverSelectorType.NativeMac }>
|
||||
{ _("optionsReceiverSelectorTypeNative") }
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</label> }
|
||||
|
||||
<label className="option option--inline">
|
||||
<div className="option__control">
|
||||
<input name="receiverSelectorWaitForConnection"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.receiverSelectorWaitForConnection }
|
||||
onChange={ this.handleInputChange } />
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{ _("optionsReceiverSelectorWaitForConnection") }
|
||||
</div>
|
||||
<div className="option__description">
|
||||
{ _("optionsReceiverSelectorWaitForConnectionDescription") }
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className="option option--inline">
|
||||
<div className="option__control">
|
||||
<input name="receiverSelectorCloseIfFocusLost"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.receiverSelectorCloseIfFocusLost }
|
||||
onChange={ this.handleInputChange } />
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{ _("optionsReceiverSelectorCloseIfFocusLost") }
|
||||
</div>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
@@ -219,10 +294,12 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
</p>
|
||||
|
||||
<label className="option option--inline">
|
||||
<input name="userAgentWhitelistEnabled"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.userAgentWhitelistEnabled }
|
||||
onChange={ this.handleInputChange } />
|
||||
<div className="option__control">
|
||||
<input name="userAgentWhitelistEnabled"
|
||||
type="checkbox"
|
||||
checked={ this.state.options.userAgentWhitelistEnabled }
|
||||
onChange={ this.handleInputChange } />
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{ _("optionsUserAgentWhitelistEnabled") }
|
||||
</div>
|
||||
@@ -232,10 +309,12 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
<div className="option__label">
|
||||
{ _("optionsUserAgentWhitelistContent") }
|
||||
</div>
|
||||
<EditableList data={ this.state.options.userAgentWhitelist }
|
||||
onChange={ this.handleWhitelistChange }
|
||||
itemPattern={ REMOTE_MATCH_PATTERN_REGEX }
|
||||
itemPatternError={ this.getWhitelistItemPatternError } />
|
||||
<div className="option__control">
|
||||
<EditableList data={ this.state.options.userAgentWhitelist }
|
||||
onChange={ this.handleWhitelistChange }
|
||||
itemPattern={ REMOTE_MATCH_PATTERN_REGEX }
|
||||
itemPatternError={ this.getWhitelistItemPatternError } />
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
@@ -311,10 +390,17 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
||||
}
|
||||
|
||||
private handleInputChange (ev: React.ChangeEvent<HTMLInputElement>) {
|
||||
const { target } = ev;
|
||||
this.setState(currentState => {
|
||||
currentState.options[ev.target.name] = getInputValue(ev.target);
|
||||
return currentState;
|
||||
});
|
||||
}
|
||||
|
||||
private handleReceiverSelectorTypeChange (
|
||||
ev: React.ChangeEvent<HTMLSelectElement>) {
|
||||
|
||||
this.setState(currentState => {
|
||||
currentState.options[target.name] = getInputValue(target);
|
||||
currentState.options[ev.target.name] = parseInt(ev.target.value);
|
||||
return currentState;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
box-shadow: 0 0 1.5px 1px red;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
#form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -27,7 +31,6 @@
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
|
||||
|
||||
.bridge {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
margin-bottom: 10px;
|
||||
@@ -172,14 +175,12 @@
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.category > .category {
|
||||
padding: 5px 0;
|
||||
box-shadow: inset 2px 0 0 0 var(--border-color);
|
||||
}
|
||||
|
||||
.category > .category > .category__name,
|
||||
.category > .category > .category__description {
|
||||
margin-inline-start: 16px;
|
||||
.category > hr {
|
||||
border: initial;
|
||||
border-top: 1px solid var(--border-color);
|
||||
grid-column: span 2;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.category__name {
|
||||
@@ -210,8 +211,26 @@
|
||||
}
|
||||
|
||||
.option--inline {
|
||||
display: block;
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-column-start: 2;
|
||||
grid-template-columns: min-content 1fr;
|
||||
grid-template-rows: min-content min-content;
|
||||
grid-template-areas:
|
||||
"input label"
|
||||
". description";
|
||||
}
|
||||
|
||||
.option--inline > input {
|
||||
grid-area: input;
|
||||
width: 16px;
|
||||
}
|
||||
.option--inline > .option__label {
|
||||
grid-area: label;
|
||||
text-align: initial;
|
||||
}
|
||||
.option--inline > .option__description {
|
||||
grid-area: description;
|
||||
}
|
||||
|
||||
.option__label {
|
||||
@@ -219,7 +238,16 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.option > input {
|
||||
.option__description {
|
||||
color: var(--secondary-color);
|
||||
font-size: smaller;
|
||||
grid-column: span 2;
|
||||
margin: 5px 0;
|
||||
max-width: 45ch;
|
||||
}
|
||||
|
||||
.option > input,
|
||||
.option > select {
|
||||
align-self: center;
|
||||
justify-self: flex-start;
|
||||
margin-inline-start: initial;
|
||||
@@ -239,9 +267,8 @@
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.editable-list__view-button,
|
||||
.editable-list__save-raw-button {
|
||||
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.editable-list hr {
|
||||
@@ -266,10 +293,10 @@
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.editable-list__item:nth-child(even):not(:last-child) {
|
||||
.editable-list__item:nth-child(even) {
|
||||
background-color: -moz-eventreerow;
|
||||
}
|
||||
.editable-list__item:nth-child(odd):not(:last-child) {
|
||||
.editable-list__item:nth-child(odd) {
|
||||
background-color: -moz-oddtreerow;
|
||||
}
|
||||
|
||||
@@ -282,6 +309,10 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.editable-list__title + button {
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.editable-list__edit-field {
|
||||
width: -moz-available;
|
||||
margin-inline-end: 1em;
|
||||
@@ -294,6 +325,5 @@
|
||||
}
|
||||
|
||||
.editable-list__add-button {
|
||||
align-self: end;
|
||||
margin-top: 5px;
|
||||
margin-inline-end: auto;
|
||||
}
|
||||
|
||||
@@ -22,3 +22,11 @@ button,
|
||||
select {
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
height: 16px;
|
||||
margin-bottom: 1px;
|
||||
margin-top: 1px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user