Fix RTL issues (#2648)

* Convert home-assistant-main to Lit/TS

* different approach

* LRT RTL

* Lint

* RTL fix for generic entity row

* Remove fetching from selectedLanguage

* RTL the RTL languages in the picker

* Fix drawer adjust to RTL
This commit is contained in:
Paulus Schoutsen 2019-02-01 12:22:11 -08:00 committed by GitHub
parent e2ff51f425
commit 2afc8607c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 245 additions and 205 deletions

View File

@ -365,18 +365,12 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
computeDate(data) {
const date = new Date(data);
return date.toLocaleDateString(
this.hass.selectedLanguage || this.hass.language,
{ weekday: "short" }
);
return date.toLocaleDateString(this.hass.language, { weekday: "short" });
}
computeTime(data) {
const date = new Date(data);
return date.toLocaleTimeString(
this.hass.selectedLanguage || this.hass.language,
{ hour: "numeric" }
);
return date.toLocaleTimeString(this.hass.language, { hour: "numeric" });
}
_computeRTL(hass) {

View File

@ -17,6 +17,7 @@ import "./ha-icon";
import isComponentLoaded from "../common/config/is_component_loaded";
import { HomeAssistant, Panel } from "../types";
import { fireEvent } from "../common/dom/fire_event";
import { DEFAULT_PANEL } from "../common/const";
const computeInitials = (name: string) => {
if (!name) {
@ -82,7 +83,12 @@ const computePanels = (hass: HomeAssistant) => {
*/
class HaSidebar extends LitElement {
public hass?: HomeAssistant;
public defaultPage?: string;
public _defaultPage?: string;
constructor() {
super();
this._defaultPage = localStorage.defaultPage || DEFAULT_PANEL;
}
protected render() {
const hass = this.hass;
@ -114,8 +120,8 @@ class HaSidebar extends LitElement {
<paper-listbox attr-for-selected="data-panel" .selected=${hass.panelUrl}>
<a
href="${computeUrl(this.defaultPage)}"
data-panel=${this.defaultPage}
href="${computeUrl(this._defaultPage)}"
data-panel=${this._defaultPage}
tabindex="-1"
>
<paper-icon-item>
@ -214,7 +220,7 @@ class HaSidebar extends LitElement {
static get properties(): PropertyDeclarations {
return {
hass: {},
defaultPage: {},
_defaultPage: {},
};
}

View File

@ -190,7 +190,7 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) {
yaxe.maxWidth = yaxe.chart.width * 0.18;
},
position: this.hass.translationMetadata.translations[
this.hass.selectedLanguage || this.hass.language
this.hass.language
].isRTL
? "right"
: "left",

View File

@ -178,20 +178,18 @@ class MoreInfoWeather extends LocalizeMixin(PolymerElement) {
provider === "Data provided by OpenWeatherMap"
) {
if (new Date().getDay() === date.getDay()) {
return date.toLocaleTimeString(
this.hass.selectedLanguage || this.hass.language,
{ hour: "numeric" }
);
return date.toLocaleTimeString(this.hass.language, { hour: "numeric" });
}
return date.toLocaleDateString(
this.hass.selectedLanguage || this.hass.language,
{ weekday: "long", hour: "numeric" }
);
return date.toLocaleDateString(this.hass.language, {
weekday: "long",
hour: "numeric",
});
}
return date.toLocaleDateString(
this.hass.selectedLanguage || this.hass.language,
{ weekday: "long", month: "short", day: "numeric" }
);
return date.toLocaleDateString(this.hass.language, {
weekday: "long",
month: "short",
day: "numeric",
});
}
getUnit(measure) {

View File

@ -1,16 +0,0 @@
import { storeState } from "../../util/ha-pref-storage";
export default (superClass) =>
class extends superClass {
firstUpdated(changedProps) {
super.firstUpdated(changedProps);
this.addEventListener("hass-dock-sidebar", (e) =>
this._handleDockSidebar(e)
);
}
_handleDockSidebar(ev) {
this._updateHass({ dockedSidebar: ev.detail.dock });
storeState(this.hass);
}
};

View File

@ -0,0 +1,30 @@
import { storeState } from "../../util/ha-pref-storage";
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
import { HASSDomEvent } from "../../common/dom/fire_event";
interface DockSidebarParams {
dock: boolean;
}
declare global {
// for fire event
interface HASSDomEvents {
"hass-dock-sidebar": DockSidebarParams;
}
// for add event listener
interface HTMLElementEventMap {
"hass-dock-sidebar": HASSDomEvent<DockSidebarParams>;
}
}
export default (superClass: Constructor<LitElement & HassBaseEl>) =>
class extends superClass {
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
this.addEventListener("hass-dock-sidebar", (ev) => {
this._updateHass({ dockedSidebar: ev.detail.dock });
storeState(this.hass);
});
}
};

View File

@ -4,6 +4,8 @@ import { storeState } from "../../util/ha-pref-storage";
import { Constructor, LitElement } from "lit-element";
import { HassBaseEl } from "./hass-base-mixin";
import { computeLocalize } from "../../common/translations/localize";
import { computeRTL } from "../../common/util/compute_rtl";
import { HomeAssistant } from "../../types";
/*
* superClass needs to contain `this.hass` and `this._updateHass`.
@ -22,6 +24,7 @@ export default (superClass: Constructor<LitElement & HassBaseEl>) =>
protected hassConnected() {
super.hassConnected();
this._loadBackendTranslations();
this.style.direction = computeRTL(this.hass!) ? "rtl" : "ltr";
}
protected hassReconnected() {
@ -79,15 +82,17 @@ export default (superClass: Constructor<LitElement & HassBaseEl>) =>
...data,
},
};
this._updateHass({
language,
resources,
localize: computeLocalize(this, language, resources),
});
const changes: Partial<HomeAssistant> = { resources };
if (language === this.hass!.language) {
changes.localize = computeLocalize(this, language, resources);
}
this._updateHass(changes);
}
private _selectLanguage(event) {
this._updateHass({ selectedLanguage: event.detail.language });
const language: string = event.detail.language;
this._updateHass({ language, selectedLanguage: language });
this.style.direction = computeRTL(this.hass!) ? "rtl" : "ltr";
storeState(this.hass);
this._loadResources();
this._loadBackendTranslations();

View File

@ -1,152 +0,0 @@
import "@polymer/app-layout/app-drawer-layout/app-drawer-layout";
import "@polymer/app-layout/app-drawer/app-drawer";
import "@polymer/app-route/app-route";
import "@polymer/iron-media-query/iron-media-query";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../util/ha-url-sync";
import "./partial-panel-resolver";
import EventsMixin from "../mixins/events-mixin";
import NavigateMixin from "../mixins/navigate-mixin";
import { computeRTL } from "../common/util/compute_rtl";
import { DEFAULT_PANEL } from "../common/const";
import(/* webpackChunkName: "ha-sidebar" */ "../components/ha-sidebar");
import(/* webpackChunkName: "voice-command-dialog" */ "../dialogs/ha-voice-command-dialog");
const NON_SWIPABLE_PANELS = ["kiosk", "map"];
class HomeAssistantMain extends NavigateMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<style>
:host {
color: var(--primary-text-color);
/* remove the grey tap highlights in iOS on the fullscreen touch targets */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
:host([rtl]) {
direction: rtl;
}
partial-panel-resolver,
ha-sidebar {
/* allow a light tap highlight on the actual interface elements */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
}
partial-panel-resolver {
height: 100%;
}
</style>
<ha-url-sync hass="[[hass]]"></ha-url-sync>
<ha-voice-command-dialog
hass="[[hass]]"
id="voiceDialog"
></ha-voice-command-dialog>
<iron-media-query query="(max-width: 870px)" query-matches="{{narrow}}">
</iron-media-query>
<app-drawer-layout
fullbleed=""
force-narrow="[[computeForceNarrow(narrow, dockedSidebar)]]"
responsive-width="0"
>
<app-drawer
id="drawer"
align="start"
slot="drawer"
disable-swipe="[[_computeDisableSwipe(hass)]]"
swipe-open="[[!_computeDisableSwipe(hass)]]"
persistent="[[dockedSidebar]]"
>
<ha-sidebar
hass="[[hass]]"
default-page="[[_defaultPage]]"
></ha-sidebar>
</app-drawer>
<partial-panel-resolver
narrow="[[narrow]]"
hass="[[hass]]"
route="[[route]]"
show-menu="[[dockedSidebar]]"
></partial-panel-resolver>
</app-drawer-layout>
`;
}
static get properties() {
return {
hass: Object,
narrow: Boolean,
route: {
type: Object,
observer: "_routeChanged",
},
dockedSidebar: {
type: Boolean,
computed: "computeDockedSidebar(hass)",
},
rtl: {
type: Boolean,
reflectToAttribute: true,
computed: "_computeRTL(hass)",
},
};
}
ready() {
super.ready();
this._defaultPage = localStorage.defaultPage || DEFAULT_PANEL;
this.addEventListener("hass-open-menu", () => this.handleOpenMenu());
this.addEventListener("hass-close-menu", () => this.handleCloseMenu());
this.addEventListener("hass-start-voice", (ev) =>
this.handleStartVoice(ev)
);
}
_routeChanged() {
if (this.narrow) {
this.$.drawer.close();
}
}
handleStartVoice(ev) {
ev.stopPropagation();
this.$.voiceDialog.opened = true;
}
handleOpenMenu() {
if (this.narrow) {
this.$.drawer.open();
} else {
this.fire("hass-dock-sidebar", { dock: true });
}
}
handleCloseMenu() {
this.$.drawer.close();
if (this.dockedSidebar) {
this.fire("hass-dock-sidebar", { dock: false });
}
}
computeForceNarrow(narrow, dockedSidebar) {
return narrow || !dockedSidebar;
}
computeDockedSidebar(hass) {
return hass.dockedSidebar;
}
_computeDisableSwipe(hass) {
return NON_SWIPABLE_PANELS.indexOf(hass.panelUrl) !== -1;
}
_computeRTL(hass) {
return computeRTL(hass);
}
}
customElements.define("home-assistant-main", HomeAssistantMain);

View File

@ -0,0 +1,151 @@
import {
LitElement,
html,
TemplateResult,
PropertyDeclarations,
CSSResult,
css,
PropertyValues,
} from "lit-element";
import "@polymer/app-layout/app-drawer-layout/app-drawer-layout";
import "@polymer/app-layout/app-drawer/app-drawer";
// Not a duplicate, it's for typing
// tslint:disable-next-line
import { AppDrawerElement } from "@polymer/app-layout/app-drawer/app-drawer";
import "@polymer/app-route/app-route";
import "@polymer/iron-media-query/iron-media-query";
import "../util/ha-url-sync";
import "./partial-panel-resolver";
import { HomeAssistant, Route } from "../types";
import { fireEvent } from "../common/dom/fire_event";
import { PolymerChangedEvent } from "../polymer-types";
import(/* webpackChunkName: "ha-sidebar" */ "../components/ha-sidebar");
import(/* webpackChunkName: "voice-command-dialog" */ "../dialogs/ha-voice-command-dialog");
const NON_SWIPABLE_PANELS = ["kiosk", "map"];
class HomeAssistantMain extends LitElement {
public hass?: HomeAssistant;
public route?: Route;
private _narrow?: boolean;
static get properties(): PropertyDeclarations {
return {
hass: {},
narrow: {},
route: {},
};
}
protected render(): TemplateResult | void {
const hass = this.hass;
if (!hass) {
return;
}
const disableSwipe = NON_SWIPABLE_PANELS.indexOf(hass.panelUrl) !== -1;
return html`
<ha-url-sync .hass=${hass}></ha-url-sync>
<ha-voice-command-dialog .hass=${hass}></ha-voice-command-dialog>
<iron-media-query
query="(max-width: 870px)"
query-matches-changed=${this._narrowChanged}
></iron-media-query>
<app-drawer-layout
fullbleed
.forceNarrow=${this._narrow || !hass.dockedSidebar}
responsive-width="0"
>
<app-drawer
id="drawer"
align="start"
slot="drawer"
.disableSwipe=${disableSwipe}
.swipeOpen=${!disableSwipe}
.persistent=${hass.dockedSidebar}
>
<ha-sidebar .hass=${hass}></ha-sidebar>
</app-drawer>
<partial-panel-resolver
.narrow=${this._narrow}
.hass=${hass}
.route=${this.route}
.showMenu=${hass.dockedSidebar}
></partial-panel-resolver>
</app-drawer-layout>
`;
}
protected firstUpdated() {
this.addEventListener("hass-open-menu", () => {
if (this._narrow) {
this.drawer.open();
} else {
fireEvent(this, "hass-dock-sidebar", { dock: true });
}
});
this.addEventListener("hass-close-menu", () => {
this.drawer.close();
if (this.hass!.dockedSidebar) {
fireEvent(this, "hass-dock-sidebar", { dock: false });
}
});
this.addEventListener("hass-start-voice", () => {
(this.voiceDialog as any).opened = true;
});
}
protected updated(changedProps: PropertyValues) {
super.updated(changedProps);
if (changedProps.has("route") && this._narrow) {
this.drawer.close();
}
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
// Make app-drawer adjust to a potential LTR/RTL change
if (oldHass && oldHass.language !== this.hass!.language) {
this.drawer._resetPosition();
}
}
private _narrowChanged(ev: PolymerChangedEvent<boolean>) {
this._narrow = ev.detail.value;
}
private get drawer(): AppDrawerElement {
return this.shadowRoot!.querySelector("app-drawer")!;
}
private get voiceDialog() {
return this.shadowRoot!.querySelector("ha-voice-command-dialog")!;
}
static get styles(): CSSResult {
return css`
:host {
color: var(--primary-text-color);
/* remove the grey tap highlights in iOS on the fullscreen touch targets */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
partial-panel-resolver,
ha-sidebar {
/* allow a light tap highlight on the actual interface elements */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
}
partial-panel-resolver {
height: 100%;
}
`;
}
}
customElements.define("home-assistant-main", HomeAssistantMain);

View File

@ -9,9 +9,11 @@ import {
html,
css,
CSSResult,
PropertyValues,
} from "lit-element";
import { HomeAssistant } from "../../../types";
import { EntitiesCardEntityConfig } from "../cards/hui-entities-card";
import { computeRTL } from "../../../common/util/compute_rtl";
class HuiGenericEntityRow extends LitElement {
public hass?: HomeAssistant;
@ -76,6 +78,13 @@ class HuiGenericEntityRow extends LitElement {
};
}
protected updated(changedProps: PropertyValues) {
super.updated(changedProps);
if (changedProps.has("hass")) {
this.toggleAttribute("rtl", computeRTL(this.hass!));
}
}
static get styles(): CSSResult {
return css`
:host {
@ -119,6 +128,14 @@ class HuiGenericEntityRow extends LitElement {
state-badge {
flex: 0 0 40px;
}
:host([rtl]) .flex {
margin-left: 0;
margin-right: 16px;
}
:host([rtl]) .flex ::slotted(*) {
margin-left: 0;
margin-right: 8px;
}
`;
}
}

View File

@ -21,6 +21,12 @@ class HaPickLanguageRow extends LocalizeMixin(EventsMixin(PolymerElement)) {
a {
color: var(--primary-color);
}
paper-item {
direction: ltr;
}
paper-item[is-rtl] {
direction: rtl;
}
</style>
<ha-settings-row narrow="[[narrow]]">
<span slot="heading"
@ -43,9 +49,9 @@ class HaPickLanguageRow extends LocalizeMixin(EventsMixin(PolymerElement)) {
selected="{{languageSelection}}"
>
<template is="dom-repeat" items="[[languages]]">
<paper-item language-tag$="[[item.tag]]"
>[[item.nativeName]]</paper-item
>
<paper-item language-tag$="[[item.key]]" is-rtl$="[[item.isRTL]]">
[[item.nativeName]]
</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
@ -76,9 +82,10 @@ class HaPickLanguageRow extends LocalizeMixin(EventsMixin(PolymerElement)) {
if (!hass || !hass.translationMetadata) {
return [];
}
return Object.keys(hass.translationMetadata.translations).map((key) => ({
tag: key,
nativeName: hass.translationMetadata.translations[key].nativeName,
const translations = hass.translationMetadata.translations;
return Object.keys(translations).map((key) => ({
key,
...translations[key],
}));
}