first commit

This commit is contained in:
Elisha Nuchi
2018-09-12 21:13:28 -04:00
parent 0dc06b79b8
commit a18779850f
18 changed files with 10302 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
// Use ES6/7 code
const onOpen = () => {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.createMenu('Dialog')
.addItem('Add sheets', 'openDialog')
.addToUi();
}
const openDialog = () => {
var html = HtmlService.createHtmlOutputFromFile('dialog');
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(html, 'Sheet Editor');
}
const getSheets = () => SpreadsheetApp
.getActive()
.getSheets();
const getActiveSheetName = () => SpreadsheetApp
.getActive()
.getSheetName();
const getSheetsData = () => {
let activeSheetName = getActiveSheetName();
return getSheets()
.map((sheet,index) => {
let sheetName = sheet.getName();
return {
text: sheetName,
sheetIndex: index,
isActive: sheetName === activeSheetName
}
});
}
const addSheet = (sheetTitle) => {
SpreadsheetApp.getActive().insertSheet(sheetTitle);
return getSheetsData();
}
const deleteSheet = (sheetIndex) => {
var sheets = getSheets();
SpreadsheetApp.getActive().deleteSheet(sheets[sheetIndex]);
return getSheetsData();
}
//Must expose public functions
global.onOpen = onOpen;
global.openDialog = openDialog;
global.getSheetsData = getSheetsData;
global.addSheet = addSheet;
global.deleteSheet = deleteSheet;
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<!-- remove/comment out these two script tags and uncomment the react imports from sidebar.html if you don't want to load react from a cdn -->
<!-- <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script> -->
<section id="index"></section>
</body>
</html>
+121
View File
@@ -0,0 +1,121 @@
import React from "react";
import ReactDOM from "react-dom";
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import css from "./styles.css";
class FormInput extends React.Component {
constructor(props) {
super(props);
this.state = {text: ""};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ text: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.text.length) return;
this.props.newSheetFormHandler(e, this.state.text)
this.setState(prevState => ({
text: ""
}));
}
render() {
return (
<div className="formBlock">
<span>Add a sheet: </span>
<form onSubmit={(e) => this.handleSubmit(e)}>
<input
onChange={this.handleChange}
value={this.state.text}
/>
</form>
</div>
);
}
}
class SheetEditor extends React.Component {
constructor(props) {
super(props);
this.state = {names: []};
this.deleteButtonHandler = this.deleteButtonHandler.bind(this);
this.newSheetFormHandler = this.newSheetFormHandler.bind(this);
}
componentDidMount() {
google.script.run
.withSuccessHandler((data) => this.setState({names: data}))
.withFailureHandler((error) => alert(error))
.getSheetsData()
}
deleteButtonHandler(e, sheetIndex) {
return google.script.run
.withSuccessHandler((data) => this.setState({names: data}))
.withFailureHandler((error) => alert(error))
.deleteSheet(sheetIndex)
}
newSheetFormHandler(e, newSheetTitle) {
google.script.run
.withSuccessHandler((data) => this.setState({names: data}))
.withFailureHandler((error) => alert(error))
.addSheet(newSheetTitle);
}
render() {
let names = this.state.names
return (
<div>
<FormInput newSheetFormHandler={this.newSheetFormHandler}/>
<ReactCSSTransitionGroup
transitionName="sheetNames"
transitionAppear={true}
transitionEnterTimeout={100}
transitionLeaveTimeout={100}>
{
names.length ?
names.map((name) => {
return (
<SheetButton name={name} deleteButtonHandler={this.deleteButtonHandler}/>
)
})
: null
}
</ReactCSSTransitionGroup>
</div>
);
}
}
class SheetButton extends React.Component {
render() {
let sheetIndex = this.props.name.sheetIndex;
let sheetName = this.props.name.text;
let isActiveSheet = this.props.name.isActive;
return (
<div className="sheetLine">
<button
onClick={(e) => this.props.deleteButtonHandler(e,sheetIndex)}
>
X
</button>
<span className={"sheetNameText " + (isActiveSheet ? "active-sheet" : "")}>
{sheetName}
</span>
</div>
)
}
}
ReactDOM.render(
<SheetEditor />,
document.getElementById("index")
);
+93
View File
@@ -0,0 +1,93 @@
@import url('https://fonts.googleapis.com/css?family=Lora|Mukta');
input {
width: 130px;
margin-left: 8px;
}
button {
-webkit-transition-duration: 0.4s; /* Safari */
background-color: #f44336;
border: 1px solid #f44336;
color: white;
display: inline-block;
font-family: 'Mukta', sans-serif;
font-size: 11px;
height: 20px;
line-height: 15px;
margin-left: 3px;
margin-right: 11px;
padding: 3px;
text-transform: uppercase;
transition-duration: 0.6s;
vertical-align: middle;
width: 20px;
}
button:hover {
background-color: white;
color: black;
}
button:active {
background-color: #fafafa;
transform: translateY(1px);
transition-duration: 0.3s;
}
button:focus {
outline: none;
}
.formBlock {
display: -webkit-box;
font-family: 'Lora', serif;
font-weight: 700;
}
.sheetLine {
line-height: 3;
height: 30px;
}
.sheetNameText {
font-size: 14px;
font-family: 'Lora', serif;
}
.sheetNameText.active-sheet {
border-bottom: 3px solid #338236;
}
/*
ReactCSSTransitionGroup styling
*/
.sheetNames-enter {
opacity: 0.01;
}
.sheetNames-enter.sheetNames-enter-active {
opacity: 1;
transition: opacity 800ms ease-in;
}
.sheetNames-leave {
opacity: 1;
}
.sheetNames-leave.sheetNames-leave-active {
opacity: 0.01;
transition: opacity 100ms ease-in;
}
.sheetNames-appear {
opacity: 0.01;
}
.sheetNames-appear.sheetNames-appear-active {
opacity: 1;
transition: opacity .5s ease-in;
}