1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-05-06 18:45:31 +02:00

Add a readonly github intergration

This commit is contained in:
Kushagra Gour 2018-11-05 22:05:13 +05:30
parent fb4fc6b37e
commit d127720a1f
4 changed files with 165 additions and 54 deletions

View File

@ -1,37 +1,68 @@
import { h } from 'preact'; import { h, Component } from 'preact';
import Modal from './Modal'; import Modal from './Modal';
import { ItemTile } from './ItemTile'; import { ItemTile } from './ItemTile';
import templates from '../templateList'; import templates from '../templateList';
export function CreateNewModal({ export class CreateNewModal extends Component {
show, render() {
closeHandler, const {
onBlankTemplateSelect, show,
onBlankFileTemplateSelect, closeHandler,
onTemplateSelect onBlankTemplateSelect,
}) { onBlankFileTemplateSelect,
return ( onImportGithubRepoSelect,
<Modal show={show} closeHandler={closeHandler} smll> onTemplateSelect
<div class="tac"> } = this.props;
<button className="btn" onClick={onBlankTemplateSelect}> return (
Start a blank creation <Modal show={show} closeHandler={closeHandler}>
</button> <div class="tac">
<button className="btn" onClick={onBlankFileTemplateSelect}> <button className="btn" onClick={onBlankTemplateSelect}>
Start a blank files creation Start a blank creation
</button> </button>
</div> <button className="btn" onClick={onBlankFileTemplateSelect}>
<hr /> Start a blank files creation
Or choose from a template: </button>
<div class="saved-items-pane__container">
{templates.map(template => ( <p>
<ItemTile <button
inline className="btn"
item={template} onClick={() =>
focusable this.setState({
onClick={onTemplateSelect.bind(null, template)} isGhRepoInputVisible: true
/> })
))} }
</div> >
</Modal> Import Github Repository
); </button>
{this.state.isGhRepoInputVisible ? (
<div>
<input ref={el => (this.ghRepoInput = el)} />
<button
className="btn"
onClick={() => {
onImportGithubRepoSelect(this.ghRepoInput.value);
}}
>
Import
</button>
</div>
) : null}
</p>
</div>
<hr />
Or choose from a template:
<div class="saved-items-pane__container">
{templates.map(template => (
<ItemTile
inline
item={template}
focusable
onClick={onTemplateSelect.bind(null, template)}
/>
))}
</div>
</Modal>
);
}
} }

View File

@ -44,8 +44,14 @@ export function FileIcon({ file }) {
/> />
); );
break; break;
case 'ts':
path: <path
fill="#2874C1"
d="M3,3H21V21H3V3M13.71,17.86C14.21,18.84 15.22,19.59 16.8,19.59C18.4,19.59 19.6,18.76 19.6,17.23C19.6,15.82 18.79,15.19 17.35,14.57L16.93,14.39C16.2,14.08 15.89,13.87 15.89,13.37C15.89,12.96 16.2,12.64 16.7,12.64C17.18,12.64 17.5,12.85 17.79,13.37L19.1,12.5C18.55,11.54 17.77,11.17 16.7,11.17C15.19,11.17 14.22,12.13 14.22,13.4C14.22,14.78 15.03,15.43 16.25,15.95L16.67,16.13C17.45,16.47 17.91,16.68 17.91,17.26C17.91,17.74 17.46,18.09 16.76,18.09C15.93,18.09 15.45,17.66 15.09,17.06L13.71,17.86M13,11.25H8V12.75H9.5V20H11.25V12.75H13V11.25Z"
/>;
break;
case 'css': case 'css':
case 'less':
path = ( path = (
<path <path
fill="rgb(95, 158, 160)" fill="rgb(95, 158, 160)"
@ -53,7 +59,15 @@ export function FileIcon({ file }) {
/> />
); );
break; break;
case 'scss':
case 'sass':
path = (
<path
fill="#CF649A"
d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M10,15.33C10.16,15.87 10.14,16.37 10,16.83C10,16.88 9.96,16.93 9.94,17C9.92,17 9.9,17.07 9.87,17.12C9.76,17.36 9.6,17.59 9.41,17.79C8.83,18.43 8,18.67 7.67,18.47C7.29,18.25 7.5,17.35 8.16,16.64C8.88,15.88 9.92,15.38 9.92,15.38V15.38L10,15.33M18.27,6.28C17.82,4.5 14.87,3.92 12.09,4.91C10.43,5.5 8.63,6.42 7.34,7.63C5.81,9.07 5.56,10.32 5.66,10.84C6,12.68 8.54,13.89 9.58,14.78V14.79C9.28,14.94 7.04,16.07 6.5,17.23C5.96,18.45 6.6,19.33 7,19.45C8.34,19.81 9.69,19.16 10.41,18.07C11.11,17.03 11.06,15.68 10.75,15C11.17,14.9 11.66,14.85 12.28,14.92C14.04,15.13 14.38,16.22 14.31,16.68C14.25,17.14 13.88,17.39 13.76,17.47C13.64,17.54 13.6,17.57 13.61,17.63C13.62,17.71 13.68,17.71 13.78,17.69C13.93,17.66 14.71,17.32 14.74,16.47C14.78,15.39 13.75,14.19 11.93,14.22C11.18,14.24 10.71,14.31 10.37,14.44L10.29,14.35C9.16,13.15 7.08,12.3 7.17,10.68C7.2,10.09 7.4,8.55 11.17,6.67C14.25,5.13 16.72,5.55 17.15,6.5C17.76,7.83 15.83,10.32 12.63,10.68C11.41,10.82 10.76,10.34 10.6,10.17C10.43,10 10.41,9.97 10.35,10C10.24,10.07 10.31,10.23 10.35,10.33C10.44,10.58 10.84,11 11.5,11.24C12.09,11.43 13.53,11.54 15.26,10.87C17.2,10.12 18.72,8.03 18.27,6.28Z"
/>
);
break;
case 'md': case 'md':
case 'markdown': case 'markdown':
path = ( path = (

View File

@ -28,7 +28,8 @@ import {
assignFilePaths, assignFilePaths,
getFileFromPath, getFileFromPath,
removeFileAtPath, removeFileAtPath,
doesFileExistInFolder doesFileExistInFolder,
importGithubRepo
} from '../fileUtils'; } from '../fileUtils';
import { itemService } from '../itemService'; import { itemService } from '../itemService';
@ -319,7 +320,7 @@ export default class App extends Component {
alertsService.add(`"${sourceItem.title}" was forked`); alertsService.add(`"${sourceItem.title}" was forked`);
trackEvent('fn', 'itemForked'); trackEvent('fn', 'itemForked');
} }
createNewItem(isFileMode = false) { createNewItem(isFileMode = false, files) {
const d = new Date(); const d = new Date();
let item = { let item = {
title: title:
@ -337,24 +338,26 @@ export default class App extends Component {
if (isFileMode) { if (isFileMode) {
item = { item = {
...item, ...item,
files: assignFilePaths([ files: assignFilePaths(
{ files || [
name: 'index.html', {
content: name: 'index.html',
'hello\n<link rel="stylesheet" href="styles/style.css">\n<script src="script.js"></script>' content:
}, 'hello\n<link rel="stylesheet" href="styles/style.css">\n<script src="script.js"></script>'
{ },
name: 'styles', {
isFolder: true, name: 'styles',
children: [{ name: 'style.css', content: '' }] isFolder: true,
}, children: [{ name: 'style.css', content: '' }]
{ name: 'script.js', content: '' }, },
{ { name: 'script.js', content: '' },
name: 'tempo', {
isFolder: true, name: 'tempo',
children: [{ name: 'main.css', content: '' }] isFolder: true,
} children: [{ name: 'main.css', content: '' }]
]) }
]
)
}; };
} else { } else {
item = { item = {
@ -1311,6 +1314,12 @@ export default class App extends Component {
}); });
this.setState({ isCreateNewModalOpen: false }); this.setState({ isCreateNewModalOpen: false });
} }
importGithubRepoSelectHandler(repoUrl) {
importGithubRepo(repoUrl).then(files => {
this.createNewItem(true, files);
this.setState({ isCreateNewModalOpen: false });
});
}
addFileHandler(fileName, isFolder) { addFileHandler(fileName, isFolder) {
let newEntry = { name: fileName, content: '' }; let newEntry = { name: fileName, content: '' };
if (isFolder) { if (isFolder) {
@ -1634,6 +1643,9 @@ export default class App extends Component {
this this
)} )}
onTemplateSelect={this.templateSelectHandler.bind(this)} onTemplateSelect={this.templateSelectHandler.bind(this)}
onImportGithubRepoSelect={this.importGithubRepoSelectHandler.bind(
this
)}
/> />
<CommandPalette <CommandPalette

View File

@ -116,3 +116,57 @@ export function getParentPath(path) {
} }
return ''; return '';
} }
/**
* Fetches the files from a github repo and returns a suitable file structure.
* @param {Promise} Promise of completition. Resolves to the files structure.
*/
export function importGithubRepo(repoUrl) {
let repoSlug, match;
if ((match = repoUrl.match(/github\.com\/([^\/]*\/[^\/]*)/))) {
repoSlug = match[1];
} else {
repoSlug = 'chinchang/github';
}
const queryString = '';
function fetchFile(filepath) {
return fetch(
`https://api.github.com/repos/${repoSlug}/contents/${filepath}${queryString}`
).then(response => response.json());
}
function fetchDir(path, currentDir) {
return fetch(
`https://api.github.com/repos/${repoSlug}/contents/${path}${queryString}`
)
.then(response => response.json())
.then(response => {
if (!response) {
return;
}
return Promise.all(
response.map(file => {
if (file.type === 'file') {
return fetchFile(`${file.path}`).then(actualFile => {
currentDir.push({
name: file.name,
content: atob(actualFile.content)
});
});
} else if (file.type === 'dir') {
const newEntry = {
name: file.name,
children: [],
isFolder: true
};
currentDir.push(newEntry);
return fetchDir(`${file.path}`, newEntry.children);
}
})
);
});
}
const files = [];
return fetchDir('', files).then(() => {
return files;
});
}