Finish the framework of settings.

This commit is contained in:
Zhongyi Tong
2017-06-28 19:09:13 +08:00
parent ffba6b68f8
commit a74b17b989
8 changed files with 377 additions and 186 deletions

View File

@@ -5,7 +5,35 @@ body {
cursor: default;
font-size: 14px;
color: #333;
background: #fff;
background: #efefef;
}
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(../fonts/MaterialIcons-Regular.ttf) format('truetype');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
/* Preferred icon size */
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
}
#content {
@@ -59,14 +87,26 @@ body {
overflow-y: scroll;
}
.server-info-container {
#server-info-container {
margin: 20px 0;
}
#new-server-container {
margin: 20px 0;
opacity: 1;
transition: opacity 0.3s;
}
.title {
padding: 4px 0 6px 0;
font-size: 18px;
color: #000;
font-weight: bold;
color: #1e1e1e;
}
.sub-title {
padding: 4px 0 6px 0;
font-weight: bold;
color: #616161;
}
img.server-info-icon {
@@ -78,22 +118,25 @@ img.server-info-icon {
}
.server-info-left {
margin-right: 20px;
margin: 10px 20px 0 0;
}
.server-info-right {
flex-grow: 1;
margin-right: 10px;
}
.server-info-row {
display: flex;
line-height: 26px;
height: 40px;
line-height: 27px;
margin: 8px 0;
height: 27px;
}
.server-info-key {
width: 40px;
margin-right: 20px;
font-weight: bold;
text-align: right;
}
@@ -102,14 +145,14 @@ img.server-info-icon {
font-size: 14px;
height: 24px;
border: none;
border-bottom: #ddd 1px solid;
border-bottom: #ededed 1px solid;
outline-width: 0;
background: transparent;
max-width: 500px;
}
.server-info-value:focus {
border-bottom: #b0d8ce 2px solid;
border-bottom: #388E3C 1px solid;
}
.actions-container {
@@ -124,12 +167,14 @@ img.server-info-icon {
.action {
display: flex;
align-items: center;
margin-right: 20px;
padding: 0 10px;
border-radius: 2px;
}
.action i {
margin-right: 5px;
font-size: 18px;
line-height: 27px;
}
.settings-pane {
@@ -154,28 +199,36 @@ img.server-info-icon {
.server-info {
display: flex;
padding: 10px;
margin: 10px 0 10px 0;
padding: 16px 30px;
margin: 10px 0 20px 0;
background: #fff;
border-radius: 2px;
width: 540px;
box-shadow: 1px 2px 4px #bcbcbc;
}
.hidden {
display: none;
height: 0 !important;
width: 0 !important;
margin: 5px !important;
opacity: 0 !important;
transition: opacity 0.3s;
}
.save-server-button {
display: inline-block;
cursor: pointer;
padding: 7px 14px;
background-color: #52c2af;
border-radius: 4px;
border: 0;
font-size: 1em;
font-weight: 600;
color: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
transition: all .2s ease;
.red {
color: #ef5350;
background: #ffebee;
border: 1px solid #ef5350;
}
.save-server-button:hover {
background-color: #32a692;
}
.green {
color: #388E3C;
background: #E8F5E9;
border: 1px solid #388E3C;
}
.grey {
color: #9E9E9E;
background: #FAFAFA;
border: 1px solid #9E9E9E;
}

View File

@@ -0,0 +1,41 @@
'use strict';
const {ipcRenderer} = require('electron');
const BaseComponent = require(__dirname + '/../../components/base.js');
class GeneralSection {
constructor(props) {
this.props = props;
}
template() {
return `
<div class="settings-pane" id="server-settings-pane">
<div class="title">Manage Servers</div>
<div class="actions-container">
<div class="action green" id="new-server-action">
<i class="material-icons">add_box</i>
<span>New Server</span>
</div>
</div>
<div id="new-server-container" class="hidden"></div>
<div class="sub-title">Existing Servers</div>
<div id="server-info-container"></div>
</div>
`;
}
init() {
this.props.$root.innerHTML = '';
this.initActions();
}
initActions() {
}
handleServerInfoChange(index) {
ipcRenderer.send('reload-main');
}
}
module.exports = GeneralSection;

View File

@@ -8,7 +8,7 @@ class PreferenceNav extends BaseComponent {
this.props = props;
this.navItems = ['General', 'Server'];
this.navItems = ['General', 'Servers'];
this.init();
}
@@ -37,7 +37,9 @@ class PreferenceNav extends BaseComponent {
registerListeners() {
for (let navItem of this.navItems) {
const $item = document.getElementById(`nav-${navItem}`);
$item.addEventListener('click', this.props.onItemSelected.bind(navItem));
$item.addEventListener('click', event => {
this.props.onItemSelected(navItem);
});
}
}

View File

@@ -0,0 +1,80 @@
'use strict';
const {ipcRenderer} = require('electron');
const BaseComponent = require(__dirname + '/../../components/base.js');
const DomainUtil = require(__dirname + '/../../utils/domain-util.js');
const Nav = require(__dirname + '/nav.js');
class NewServerForm extends BaseComponent{
constructor(props) {
super();
this.props = props;
}
template() {
return `
<div class="server-info" style="border: solid 1px #4CAF50;">
<div class="server-info-left">
<img class="server-info-icon" src="${__dirname + '../../../../img/icon.png'}"/>
</div>
<div class="server-info-right">
<div class="server-info-row">
<span class="server-info-key">Name</span>
<input class="server-info-value" placeholder="(Required)"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Url</span>
<input class="server-info-value" placeholder="(Required)"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Icon</span>
<input class="server-info-value" placeholder="(Optional)"/>
</div>
<div class="server-info-row">
<span class="server-info-key"></span>
<div class="action green server-save-action">
<i class="material-icons">check_box</i>
<span>Save</span>
</div>
</div>
</div>
</div>
`;
}
init() {
this.initForm();
this.initActions();
}
initForm() {
this.$newServerForm = this.generateNodeFromTemplate(this.template());
this.$saveServerButton = this.$newServerForm.getElementsByClassName('server-save-action')[0];
this.props.$root.innerHTML = '';
this.props.$root.appendChild(this.$newServerForm);
this.$newServerAlias = this.$newServerForm.querySelectorAll('input.server-info-value')[0];
this.$newServerUrl = this.$newServerForm.querySelectorAll('input.server-info-value')[1];
this.$newServerIcon = this.$newServerForm.querySelectorAll('input.server-info-value')[2];
}
initActions() {
this.$saveServerButton.addEventListener('click', () => {
DomainUtil.checkDomain(this.$newServerUrl.value).then(domain => {
const server = {
alias: this.$newServerAlias.value,
url: domain,
icon: this.$newServerIcon.value
};
DomainUtil.addDomain(server);
this.props.onChange(this.props.index);
}, errorMessage => {
alert(errorMessage);
});
});
}
}
module.exports = NewServerForm;

View File

@@ -1,154 +1,44 @@
'use strict';
const {ipcRenderer} = require('electron');
const BaseComponent = require(__dirname + '/js/components/base.js');
const DomainUtil = require(__dirname + '/js/utils/domain-util.js');
const Nav = require(__dirname + '/js/pages/preference/nav.js');
const ServersSection = require(__dirname + '/js/pages/preference/servers-section.js');
const GeneralSection = require(__dirname + '/js/pages/preference/general-section.js');
class PreferenceView {
constructor() {
this.$sidebarContainer = document.getElementById('sidebar');
this.$newServerButton = document.getElementById('new-server-action');
this.$saveServerButton = document.getElementById('save-server-action');
this.$reloadServerButton = document.getElementById('reload-server-action');
this.$serverInfoContainer = document.querySelector('.server-info-container');
this.$sidebarContainer = document.getElementById('sidebar');
this.$settingsContainer = document.getElementById('settings-container');
}
init() {
this.nav = new Nav({
$root: this.$sidebarContainer,
onItemSelected: this.handleNavigation
});
this.nav.activate('Server');
this.initServers();
this.initActions();
}
initServers() {
const servers = DomainUtil.getDomains();
this.$serverInfoContainer.innerHTML = servers.length ? '' : 'Add your first server to get started!';
this.$serverInfoContainer.innerHTML = servers.length ? '' : 'Add your first server to get started!';
this.initNewServerForm();
for (const i in servers) {
this.initServer(servers[i], i);
}
}
initServer(server, index) {
const {
alias,
url,
icon
} = server;
const serverInfoTemplate = `
<div class="server-info">
<div class="server-info-left">
<img class="server-info-icon" src="${icon}"/>
</div>
<div class="server-info-right">
<div class="server-info-row">
<span class="server-info-key">Name</span>
<input class="server-info-value" disabled value="${alias}"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Url</span>
<input class="server-info-value" disabled value="${url}"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Icon</span>
<input class="server-info-value" disabled value="${icon}"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Actions</span>
<div class="action server-info-value" id="delete-server-action-${index}">
<i class="material-icons">indeterminate_check_box</i>
<span>Delete</span>
</div>
</div>
</div>
</div>`;
this.$serverInfoContainer.appendChild(this.insertNode(serverInfoTemplate));
document.getElementById(`delete-server-action-${index}`).addEventListener('click', () => {
DomainUtil.removeDomain(index);
this.initServers();
// alert('Success. Reload to apply changes.');
ipcRenderer.send('reload-main');
this.$reloadServerButton.classList.remove('hidden');
});
}
initNewServerForm() {
const newServerFormTemplate = `
<div class="server-info active hidden">
<div class="server-info-left">
<img class="server-info-icon" src="https://chat.zulip.org/static/images/logo/zulip-icon-128x128.271d0f6a0ca2.png"/>
</div>
<div class="server-info-right">
<div class="server-info-row">
<span class="server-info-key">Name</span>
<input id="server-info-name" class="server-info-value" placeholder="(Required)"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Url</span>
<input id="server-info-url" spellcheck="false" class="server-info-value" placeholder="(Required)"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Icon</span>
<input id="server-info-icon" class="server-info-value" placeholder="(Optional)"/>
</div>
</div>
</div>
`;
this.$serverInfoContainer.appendChild(this.insertNode(newServerFormTemplate));
this.$newServerForm = document.querySelector('.server-info.active');
this.$newServerAlias = this.$newServerForm.querySelectorAll('input.server-info-value')[0];
this.$newServerUrl = this.$newServerForm.querySelectorAll('input.server-info-value')[1];
this.$newServerIcon = this.$newServerForm.querySelectorAll('input.server-info-value')[2];
}
initActions() {
this.$newServerButton.addEventListener('click', () => {
this.$newServerForm.classList.remove('hidden');
this.$saveServerButton.classList.remove('hidden');
this.$newServerButton.classList.add('hidden');
});
this.$saveServerButton.addEventListener('click', () => {
DomainUtil.checkDomain(this.$newServerUrl.value).then(domain => {
const server = {
alias: this.$newServerAlias.value,
url: domain,
icon: this.$newServerIcon.value
};
DomainUtil.addDomain(server);
this.$saveServerButton.classList.add('hidden');
this.$newServerButton.classList.remove('hidden');
this.$newServerForm.classList.add('hidden');
this.initServers();
// alert('Success. Reload to apply changes.');
ipcRenderer.send('reload-main');
this.$reloadServerButton.classList.remove('hidden');
}, errorMessage => {
alert(errorMessage);
});
});
this.$reloadServerButton.addEventListener('click', () => {
ipcRenderer.send('reload-main');
onItemSelected: this.handleNavigation.bind(this)
});
this.handleNavigation('General');
}
handleNavigation(navItem) {
}
insertNode(html) {
const wrapper = document.createElement('div');
wrapper.innerHTML = html;
return wrapper.firstElementChild;
this.nav.select(navItem);
switch (navItem) {
case 'Servers': {
this.section = new ServersSection({
$root: this.$settingsContainer
});
break;
}
case 'General': {
this.section = new GeneralSection({
$root: this.$settingsContainer
});
break;
}
}
this.section.init();
}
}

View File

@@ -0,0 +1,65 @@
'use strict';
const {ipcRenderer} = require('electron');
const BaseComponent = require(__dirname + '/../../components/base.js');
const DomainUtil = require(__dirname + '/../../utils/domain-util.js');
const Nav = require(__dirname + '/nav.js');
class ServerInfoForm extends BaseComponent{
constructor(props) {
super();
this.props = props;
}
template() {
return `
<div class="server-info">
<div class="server-info-left">
<img class="server-info-icon" src="${this.props.server.icon}"/>
</div>
<div class="server-info-right">
<div class="server-info-row">
<span class="server-info-key">Name</span>
<input class="server-info-value" disabled value="${this.props.server.alias}"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Url</span>
<input class="server-info-value" disabled value="${this.props.server.url}"/>
</div>
<div class="server-info-row">
<span class="server-info-key">Icon</span>
<input class="server-info-value" disabled value="${this.props.server.icon}"/>
</div>
<div class="server-info-row">
<span class="server-info-key"></span>
<div class="action red server-delete-action">
<i class="material-icons">indeterminate_check_box</i>
<span>Delete</span>
</div>
</div>
</div>
</div>
`;
}
init() {
this.initForm();
this.initActions();
}
initForm() {
this.$serverInfoForm = this.generateNodeFromTemplate(this.template());
this.$deleteServerButton = this.$serverInfoForm.getElementsByClassName('server-delete-action')[0];
this.props.$root.appendChild(this.$serverInfoForm);
}
initActions() {
this.$deleteServerButton.addEventListener('click', () => {
DomainUtil.removeDomain(this.props.index);
this.props.onChange(this.props.index);
});
}
}
module.exports = ServerInfoForm;

View File

@@ -0,0 +1,81 @@
'use strict';
const {ipcRenderer} = require('electron');
const BaseComponent = require(__dirname + '/../../components/base.js');
const DomainUtil = require(__dirname + '/../../utils/domain-util.js');
const Nav = require(__dirname + '/nav.js');
const ServerInfoForm = require(__dirname + '/server-info-form.js');
const NewServerForm = require(__dirname + '/new-server-form.js');
class ServersSection {
constructor(props) {
this.props = props;
}
template() {
return `
<div class="settings-pane" id="server-settings-pane">
<div class="title">Manage Servers</div>
<div class="actions-container">
<div class="action green" id="new-server-action">
<i class="material-icons">add_box</i>
<span>New Server</span>
</div>
</div>
<div id="new-server-container" class="hidden"></div>
<div class="sub-title">Existing Servers</div>
<div id="server-info-container"></div>
</div>
`;
}
init() {
this.initServers();
this.initActions();
}
initServers() {
this.props.$root.innerHTML = '';
const servers = DomainUtil.getDomains();
this.props.$root.innerHTML = this.template();
this.$serverInfoContainer = document.getElementById('server-info-container');
this.$newServerContainer = document.getElementById('new-server-container');
this.$newServerButton = document.getElementById('new-server-action');
this.$serverInfoContainer.innerHTML = servers.length ? '' : 'Add your first server to get started!';
this.initNewServerForm();
for (const i in servers) {
new ServerInfoForm({
$root: this.$serverInfoContainer,
server: servers[i],
index: i,
onChange: this.handleServerInfoChange.bind(this)
}).init();
}
}
initNewServerForm() {
new NewServerForm({
$root: this.$newServerContainer,
onChange: this.handleServerInfoChange.bind(this)
}).init();
}
initActions() {
this.$newServerButton.addEventListener('click', () => {
this.$newServerContainer.classList.remove('hidden');
this.$newServerButton.classList.remove('green');
this.$newServerButton.classList.add('grey');
});
}
handleServerInfoChange(index) {
ipcRenderer.send('reload-main');
}
}
module.exports = ServersSection;

View File

@@ -5,32 +5,11 @@
<meta name="viewport" content="width=device-width">
<title>Zulip - Settings</title>
<link rel="stylesheet" href="css/preference.css" type="text/css" media="screen">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div id="content">
<div id="sidebar"></div>
<div id="settings-container">
<div class="settings-pane" id="server-settings-pane">
<div class="title">Manage Servers</div>
<div class="actions-container">
<div class="action" id="new-server-action">
<i class="material-icons">add_box</i>
<span>New Server</span>
</div>
<div class="action hidden" id="save-server-action">
<button class="save-server-button">Save</button>
</div>
<div class="action hidden" id="reload-server-action">
<i class="material-icons">refresh</i>
<span>Reload to Apply Changes</span>
</div>
</div>
<div class="server-info-container">
</div>
</div>
</div>
<div id="settings-container"></div>
</div>
</body>
<script src="js/pages/preference/preference.js"></script>