reactjs打造一个web操作系统桌面界面效果代码
代码语言:html
所属分类:其他
代码描述:reactjs打造一个web操作系统桌面界面效果代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Fira+Mono"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Catamaran:900"> </head> <body style="background: #2C2F33; font-family: arial;"> <main id="reactapp"> </main> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/react.production.16.13.js"></script> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/react-dom.production.16.13.js"></script> <script> function _extends() {_extends = Object.assign || function (target) {for (var i = 1; i < arguments.length; i++) {var source = arguments[i];for (var key in source) {if (Object.prototype.hasOwnProperty.call(source, key)) {target[key] = source[key];}}}return target;};return _extends.apply(this, arguments);}const MONO_FONT = { fontFamily: "Fira Mono, monospace" }; const SANS_FONT = { fontFamily: "Open Sans, sans-serif" }; const TITLE_FONT = { fontFamily: "Catamaran, sans-serif" }; const MONOKAI_COLOURS = [ "#F8F8F0", // 0 ghost-white "#F8F8F2", // 1 light-ghost-white "#CCC", // 2 light-gray "#888", // 3 gray "#49483E", // 4 brown-gray "#282828", // 5 dark-gray "#E6DB74", // 6 yellow "#66D9EF", // 7 blue "#F92672", // 8 pink "#AE81FF", // 9 purple "#75715E", // 10 brown "#FD971F", // 11 orange "#FFD569", // 12 light-orange "#A6E22E", // 13 green "#529B2F" // 14 sea-green ]; // light dark // 0 black #383a42 #282c34 // 1 red #e45649 #e06c75 // 2 green #50a14f #98c379 // 3 yellow #c18401 #e5c07b // 4 blue #0184bc #61afef // 5 magenta #a626a4 #c678dd // 6 cyan #0997b3 #56b6c2 // 7 white #fafafa #dcdfe4 const TERMINAL_COLOURS = [ "#383a42", "#e45649", "#50a14f", "#c18401", "#0184bc", "#a626a4", "#0997b3", "#fafafa", "#282c34", "#e06c75", "#98c379", "#e5c07b", "#61afef", "#c678dd", "#56b6c2", "#dcdfe4"]; const FILE_TREE_HOBBIES = { home: { rlahd: { Hobbies: { "3D Printing": { type: "file", onDoubleClick: () => { console.log("YEAH"); }, metadata: { Created: "2019", Printer: "Ender 3", Fun: "High", Price: "High :(" }, imgUrl: "//repo.bfw.wiki/bfwrepo/icon/5da6d4920e166.png" }, Games: { "Board Games": { type: "file", metadata: { Genres: "Hidden Role, Bluffing, Co-op", Favourites: "Pandemic, Hanabi, Avalon" } }, "Video Games": { type: "file", metadata: { Genres: "RPG, FPS, MOBA, Co-op, VR", Favourites: "Portal 1+2" } }, "Tabletop Games": { type: "file", description: "Dungeon Master of a currently 3 year campaign", metadata: { Skills: "Teamwork, Leadership", Game: "Dungeons and Dragons", Edition: "5th" } } }, Books: { "Science Fiction": { "Culture Series": { type: "file", metadata: { Author: "Iain Banks" } }, "The Martian": { type: "file", metadata: { Author: "Andy Weir" } }, "Three Body Problem": { type: "file", metadata: { Author: "Cixin Liu" } }, "Hitchhikers Guide": { type: "file", metadata: { Author: "Douglas Adams" } } }, Fantasy: { "Stormlight Archive": { type: "file", metadata: { Author: "Brandon Sanderson" } }, "The Kingkiller Chronicle": { type: "file", metadata: { Author: "Patrick Rothfuss" } } } } }, "Personal Dev": { "Runescape Text": { type: "file", onDoubleClick: () => { Window.open("/"); }, description: "A little tool and Discord Bot for emulating text from a popular MMO", metadata: { Created: "2018" } }, "Spell Templates": { type: "file", onDoubleClick: () => { Window.open("/"); }, description: "A progressive web app for doing some math checking for Dungeons and Dragons grid mechanics", metadata: { Created: "2018" } }, "SenseHAT Listener": { type: "file", onDoubleClick: () => { Window.open("/"); }, description: "A frontend public controller for an 8x8 LED grid (SenseHAT) attached to a Raspberry Pi", metadata: { Created: "2019" } }, "rileylahd.me": { type: "file", onDoubleClick: () => { Window.open("/"); }, description: "Built this site essentially from scratch using React, Babel and hosted on a Raspberry Pi", metadata: { Created: "2020" } } } } } }; const EDU_HISTORY_TERMINAL = [ { string: "EDUCATION\n\n", bold: true, color: 2 }, { string: "University of Calgary ", bold: true, color: 4 }, { string: "[2013-2017]\n", bold: false, color: undefined }, { string: "\t[Calgary, AB]\n", bold: false, color: undefined }, { string: "\tGraduated 2017\n", bold: false, color: 6 }, { string: "\tBachelor of Science ", bold: true, color: 7 }, { string: "--", bold: false, color: 6 }, { string: " Computer Science\n\n", bold: true, color: 4 }, { string: "Lindsay Thurber Comprehensive High School ", bold: true, color: 4 }, { string: "[2008-2012]\n", bold: false, color: undefined }, { string: "\t[Red Deer, AB]\n", bold: false, color: undefined }, { string: "\tGraduated 2012\n", bold: false, color: 6 }, { string: "\tHonor Roll\n\n", bold: true, color: 7 }]; const WORK_HISTORY_IDE = { "README.md": { bodyChunks: [ { string: "README\n\n", bold: true, color: 8 }, { string: "Each job is a file in the left hand sidebar, each named <jobtitle>-<company>.md!\n", color: 7 }] }, "softwaredev-shaw.md": { bodyChunks: [ { string: "Software Developer II", bold: true, color: 8 }, { string: " -- ", bold: false, color: undefined }, { string: "Shaw\n", bold: true, color: 11 }, { string: "Calgary, Alberta\n", bold: true, color: 6 }, { string: "[Apr 2019 – Present]\n", bold: false, color: 13 }, { string: "--\n", bold: false, color: 0 }, { string: "Software Developer I", bold: true, color: 8 }, { string: " -- ", bold: false, color: undefined }, { string: "Shaw\n", bold: true, color: 11 }, { string: "Calgary, Alberta\n", bold: true, color: 6 }, { string: "[Jul 2017 – Apr 2019]\n", bold: false, color: 13 }, { string: "--\n", bold: false, color: 0 }, { string: "Description:\n", bold: true, color: 7 }, { string: "Worked on a multipurpose team to develop internal and external facing tools. Worked with ", bold: false, color: 1 }, { string: "Docker, Kubernetes, NodeJS, React, ", bold: true, color: 1 }, { string: "and tons of other technologies. \n", bold: false, color: 1 }, { string: "I personally created a tool for generating ", bold: false, color: 1 }, { string: "LQIP", bold: true, color: 9 }, { string: "s (Low Quality Image Previews) dynamically with a request to an API. ", bold: false, color: 1 }, { string: "The images were cached for a configurable time and could linked to or embedded.", bold: false, color: 1 }] }, "itsuppasst-cies.md": { bodyChunks: [ { string: "IT Support Asst.", bold: true, color: 8 }, { string: " -- ", bold: false, color: undefined }, { string: "Calgary Immigrant Educational Society\n", bold: true, color: 11 }, { string: "Calgary, Alberta\n", bold: true, color: 6 }, { string: "[Jun 2016 – Aug 2016]\n", bold: false, color: 13 }, { string: "--\n", bold: false, color: 0 }, { string: "Description:\n", bold: true, color: 7 }, { string: "As part of a summer contract, I performed full IT support for a staff of over 50 people across 2 locations. ", bold: false, color: 1 }, { string: "Performed all duties independently for 1 month while IT manager was on vacation. Assisted staff in setting up accounts, email, printing. ", bold: false, color: 1 }, { string: "Maintained ", bold: false, color: 1 }, { string: "SQL ", bold: true, color: 9 }, { string: "database. Managed server for all staff accounts and data. Relocated users and hardware.", bold: false, color: 1 }] }, "reznettechsupport-uofc.md": { bodyChunks: [ { string: "Reznet Tech Support", bold: true, color: 8 }, { string: " -- ", bold: false, color: undefined }, { string: "University of Calgary\n", bold: true, color: 11 }, { string: "Calgary, Alberta\n", bold: true, color: 6 }, { string: "[Sep 2013 – Jun 2014]\n", bold: false, color: 13 }, { string: "--\n", bold: false, color: 0 }, { string: "Description:\n", bold: true, color: 7 }, { string: "Assisted students with technical issues related to the university residence network and other basic issues.", bold: false, color: 1 }] }, "nonrelevant-work.md": { bodyChunks: [ { string: "Cashier", bold: true, color: 8 }, { string: " -- ", bold: false, color: undefined }, { string: "IKEA\n", bold: true, color: 11 }, { string: "Calgary, Alberta\n", bold: true, color: 6 }, { string: "[Jun 2014 – Sep 2014]\n", bold: false, color: 13 }, { string: "--\n", bold: false, color: 0 }, { string: "Description:\n", bold: true, color: 7 }, { string: "Helped customers scan purchases on regular and self checkout, assisted customers in finding things throughout the store, counted money and ensured the workplace was organized.", bold: false, color: 1 }, { string: "--\n", bold: true, color: 4 }, { string: "Hardlines Team Member", bold: true, color: 8 }, { string: " -- ", bold: false, color: undefined }, { string: "Target\n", bold: true, color: 11 }, { string: "Red Deer, Alberta\n", bold: true, color: 6 }, { string: "[May 2013 - Aug 2013]\n", bold: false, color: 13 }, { string: "--\n", bold: false, color: 0 }, { string: "Description:\n", bold: true, color: 7 }, { string: "Tasked with stocking shelves, assisting customers, working the cash register and organizing displays and shelves. Worked cooperatively with many other team members on a daily basis.", bold: false, color: 1 }, { string: "--\n", bold: true, color: 4 }, { string: "Shop Hand", bold: true, color: 8 }, { string: " -- ", bold: false, color: undefined }, { string: "Source Energy Sales & Rentals\n", bold: true, color: 11 }, { string: "Blackfalds, Alberta\n", bold: true, color: 6 }, { string: "[Jul 2010 - Oct 2012]\n", bold: false, color: 13 }, { string: "--\n", bold: false, color: 0 }, { string: "Description:\n", bold: true, color: 7 }, { string: "As a part time job while in high school I was tasked with cleaning the shop on the evenings and weekends, as well as doing miscellaneous labour. Occasionally ran errands and picked up office supplies etc.", bold: false, color: 1 }, { string: "--\n", bold: true, color: 4 }, { string: "Server", bold: true, color: 8 }, { string: " -- ", bold: false, color: undefined }, { string: "Tim Hortons\n", bold: true, color: 11 }, { string: "Red Deer, Alberta\n", bold: true, color: 6 }, { string: "[Nov 2008 - Jul 2010]\n", bold: false, color: 13 }, { string: "--\n", bold: false, color: 0 }, { string: "Description:\n", bold: true, color: 7 }, { string: "Was tasked with handling cash and operating the cash register as well as taking orders for customers and preparing their food both in the storefront and drive thru.", bold: false, color: 1 }, { string: "--\n", bold: true, color: 4 }] } }; class Site extends React.Component { constructor(props) { super(props); this.state = { windows: {}, heldWindow: undefined, windowZOrder: [], activeWindow: undefined, windowCounter: 0 }; this.newWindow = function () { let winSet = this.state.windows; let counter = this.state.windowCounter; let id = "" + (counter + 1); let newWindow = { pos: { x: Math.random() * (window.innerWidth * 0.9), y: Math.random() * (window.innerHeight - 200) }, id: id, title: counter % 2 == 0 ? "Terminal " + id : id, folded: false, hidden: false, type: counter % 2 == 0 ? "terminal" : "default", props: {} }; if (newWindow.type === "terminal") { newWindow.props.bodyChunks = [ { string: "pi@thor", bold: true, color: 0 }, { string: ":" }, { string: "~/rileylahddotme ", bold: true, color: 1 }, { string: "python3 -m http.server\n" }, { string: "Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...\n" }, { string: '10.0.0.117 - - [24/Jul/2020 15:12:40] "GET / HTTP/1.1" 200 -\n' }, { string: '10.0.0.117 - - [24/Jul/2020 15:12:40] "GET /js/main.js HTTP/1.1" 200 -\n' }, { string: '10.0.0.117 - - [24/Jul/2020 15:12:40] "GET /js/rileylahddotme-react.min.js HTTP/1.1" 200 -\n' }, { string: "10.0.0.117 - - [24/Jul/2020 15:12:40] code 404, message File not found\n" }, { string: '10.0.0.117 - - [24/Jul/2020 15:12:40] "GET /favicon.ico HTTP/1.1" 404 -\n' }]; } newWindow.children = React.createElement("div", { style: { backgroundColor: "rgba(0,0,0,0.5)", height: "250px", width: "200px", color: "rgb(75,75,75)" } }, "Test"); winSet[id] = newWindow; this.setState({ windows: winSet, windowCounter: counter + 1 }); this.makeWindowActive(new Event("dummy"), id); }; this.eduWindow = function () { let winSet = this.state.windows; let counter = this.state.windowCounter; let id = "edu"; if (winSet[id]) { winSet[id].folded = false; winSet[id].hidden = false; this.setState({ windows: winSet }); this.makeWindowActive(new Event("dummy"), id); return; } let newWindow = { pos: { x: Math.random() * 200, y: Math.random() * 200 }, id: id, title: "", folded: false, hidden: false, type: "terminal", props: {} }; newWindow.props.bodyChunks = EDU_HISTORY_TERMINAL; winSet[id] = newWindow; this.setState({ windows: winSet }); }; this.ideWindow = function () { let winSet = this.state.windows; let counter = this.state.windowCounter; let id = "ide"; if (winSet[id]) { winSet[id].folded = false; winSet[id].hidden = false; this.setState({ windows: winSet }); this.makeWindowActive(new Event("dummy"), id); return; } let newWindow = { pos: { x: Math.random() * 200, y: Math.random() * 200 }, id: id, title: "", folded: false, hidden: false, type: "ide", props: {} }; newWindow.props.windowHeight = "500px"; newWindow.props.windowWidth = "700px"; newWindow.props.defaultCurrentTab = "README.md"; newWindow.props.files = WORK_HISTORY_IDE; winSet[id] = newWindow; this.setState({ windows: winSet }); }; this.browserWindow = function () { let winSet = this.state.windows; let counter = this.state.windowCounter; let id = "browser"; if (winSet[id]) { winSet[id].folded = false; winSet[id].hidden = false; this.setState({ windows: winSet }); this.makeWindowActive(new Event("dummy"), id); return; } let newWindow = { pos: { x: Math.random() * 200, y: Math.random() * 200 }, id: id, title: "", folded: false, hidden: false, type: "browser", props: { startUrl: "helloworld.com" }, children: React.createElement("div", { style: { height: "300px", width: "600px", background: "green" } }, React.createElement("div", { style: { display: "flex", height: "100%", flexDirection: "column", justifyContent: "center" } }, React.createElement("div", { style: { margin: "0px auto", fontSize: "30px", fontWeight: "bold", color: "white", letterSpacing: ".5em", paddingLeft: ".5em", ...TITLE_FONT } }, "RILEY LAHD"), React.createElement("div", { style: { margin: "0px auto", display: "flex", flexDirection: "row", justifyContent: "space-evenly", minWidth: "50%" } }, React.createElement("a", { href: "#", style: {} }, "A"), React.createElement("a", { href: "#", style: {} }, "B"), React.createElement("a", { href: "#", style: {} }, "C"), React.createElement("a", { href: "mailto:marrysix@gmail.com", style: {} }, "D"), React.createElement("a", { href: "#", style: {} }, "E")))) }; // links: github, linkedin, codepen, email, keybase winSet[id] = newWindow; this.setState({ windows: winSet }); }; this.fileExplorerWindow = function () { let winSet = this.state.windows; let counter = this.state.windowCounter; let id = "fileexplorer"; if (winSet[id]) { winSet[id].folded = false; winSet[id].hidden = false; this.setState({ windows: winSet }); this.makeWindowActive(new Event("dummy"), id); return; } let newWindow = { pos: { x: Math.random() * 200, y: Math.random() * 200 }, id: id, title: "", folded: false, hidden: false, type: "fileexplorer", props: { startPath: "/home/rlahd", fileTree: FILE_TREE_HOBBIES } }; winSet[id] = newWindow; this.setState({ windows: winSet }); }; this.grabWindow = function (ev, id) { ev.preventDefault(); this.makeWindowActive(ev, id); if (ev.targetTouches) { ev = ev.targetTouches[0]; } this.setState({ heldWindow: id, windowPickupPos: { x: ev.pageX, y: ev.pageY } }); }; this.releaseWindow = function () { this.setState({ heldWindow: undefined }); }; this.moveWindow = function (ev) { ev.preventDefault(); if (!this.state.windows[this.state.heldWindow]) { this.releaseWindow(); return; } let oldPos = this.state.windows[this.state.heldWindow].pos; if (ev.targetTouches) { ev = ev.changedTouches[0]; console.log("MOVE", { x: ev.pageX, y: ev.pageX }); ev.movementX = ev.pageX - this.state.windowPickupPos.x; ev.movementY = ev.pageY - this.state.windowPickupPos.y; } let newPos = { x: oldPos.x + ev.movementX, y: oldPos.y + ev.movementY }; let newWindows = { ...this.state.windows }; newWindows[this.state.heldWindow].pos = newPos; this.setState({ windows: newWindows, windowPickupPos: { x: ev.pageX, y: ev.pageY } }); }; this.makeWindowActive = function (ev, id) { ev.stopPropagation(); let zOrder = this.state.windowZOrder; zOrder = zOrder.filter(x => { return x !== id; }); zOrder = [...zOrder, id]; this.setState({ windowZOrder: zOrder, activeWindow: id }); }; this.startDeleteWindow = function (ev, id) { ev.stopPropagation(); let winSet = this.state.windows; winSet[id].closing = true; this.setState({ windows: winSet }); setTimeout( (ev, id) => { this.deleteWindow(ev, id); }, 200, ev, id); }; this.deleteWindow = function (ev, id) { ev.stopPropagation(); let winSet = this.state.windows; delete winSet[id]; let zOrder = this.state.windowZOrder; zOrder = zOrder.filter(x => { return x !== id; }); this.setState({ windows: winSet, heldWindow: undefined, windowZOrder: zOrder }); }; this.toggleFoldWindow = function (ev, id) { ev.stopPropagation(); let winSet = this.state.windows; winSet[id].folded = !winSet[id].folded; this.setState({ windows: winSet }); }; this.hideWindow = function (ev, id) { ev.stopPropagation(); let winSet = this.state.windows; winSet[id].hidden = true; this.setState({ windows: winSet }); }; this.showWindow = function (ev, id) { ev.stopPropagation(); let winSet = this.state.windows; winSet[id].hidden = false; this.setState({ windows: winSet }); }; } componentDidMount() { let releaseWindow = function () { this.releaseWindow(); }.bind(this); window.addEventListener("mouseup", releaseWindow); window.addEventListener("touchend", releaseWindow); let mvWindow = function (ev) { if (this.state.heldWindow !== undefined) { this.moveWindow(ev); } }.bind(this); window.addEventListener("mousemove", mvWindow); window.addEventListener("touchmove", mvWindow); } render() { let windows = Object.entries(this.state.windows).map(w => { let globalProps = { title: w[1].title, topPos: w[1].pos.y, leftPos: w[1].pos.x, grabWindow: ev => { this.grabWindow(ev, w[1].id); }, isHeld: w[1].id === this.state.heldWindow, isHidden: w[1].hidden, isFolded: w[1].folded, makeActive: ev => { this.makeWindowActive(ev, w[1].id); }, isActive: w[1].id === this.state.activeWindow, layer: this.state.windowZOrder.indexOf(w[1].id), closing: w[1].closing, close: ev => { this.startDeleteWindow(ev, w[1].id); }, toggleFold: ev => { this.toggleFoldWindow(ev, w[1].id); }, hide: ev => { this.hideWindow(ev, w[1].id); } }; if (w[1].type === "terminal") { return React.createElement(TerminalWindow, _extends({}, globalProps, w[1].props)); } else if (w[1].type === "ide") { return React.createElement(IDEWindow, _extends({}, globalProps, w[1].props)); } else if (w[1].type === "browser") { return ( React.createElement(BrowserWindow, _extends({}, globalProps, w[1].props), w[1].children)); } else if (w[1].type === "fileexplorer") { return ( React.createElement(FileExplorerWindow, _extends({}, globalProps, w[1].props))); } else { return React.createElement(Window, globalProps, w[1].children); } }); return ( React.createElement("div", { style: { width: "100vw", height: "100vh", overflow: "hidden", position: "absolute", top: 0, left: 0, zIndex: 0 } }, React.createElement("div", null, React.createElement("br", null), windows, React.createElement(Desktop, { clearSelected: () => { this.setState({ selectedShortcut: undefined }); } }, React.createElement(DesktopShortcut, { name: "Education", imgUrl: "//repo.bfw.wiki/bfwrepo/icon/5f7d03be2a55f.png", isSelected: this.state.selectedShortcut === "EducationShortcut", setSelected: () => { this.setState({ selectedShortcut: "EducationShortcut" }); }, onDoubleClick: this.eduWindow.bind(this) }), React.createElement(DesktopShortcut, { name: "IDE", imgUrl: "//repo.bfw.wiki/bfwrepo/icon/5f7d03118a427.png", isSelected: this.state.selectedShortcut === "IDEShortcut", setSelected: () => { this.setState({ selectedShortcut: "IDEShortcut" }); }, onDoubleClick: this.ideWindow.bind(this) }), React.createElement(DesktopShortcut, { name: "Browser", imgUrl: "//repo.bfw.wiki/bfwrepo/icon/5df873f50a8c7.png", isSelected: this.state.selectedShortcut === "BrowserShortcut", setSelected: () => { this.setState({ selectedShortcut: "BrowserShortcut" }); }, onDoubleClick: this.browserWindow.bind(this) }), React.createElement(DesktopShortcut, { name: "Files", imgUrl: "//repo.bfw.wiki/bfwrepo/icon/5d835147aa4b2.png", isSelected: this.state.selectedShortcut === "FileShortcut", setSelected: () => { this.setState({ selectedShortcut: "FileShortcut" }); }, onDoubleClick: this.fileExplorerWindow.bind(this) })), React.createElement(Dock, null, React.createElement(DockButton, { onClick: this.newWindow.bind(this) }, React.createElement("img", { src: "//repo.bfw.wiki/bfwrepo/icon/5f7d03be2a55f.png", style: { height: "55px" } })), React.createElement(DockButton, { onClick: this.eduWindow.bind(this), isOpen: this.state.windows.edu }, React.createElement("img", { src: "//repo.bfw.wiki/bfwrepo/icon/5f7d03118a427.png", style: { height: "55px" } })), React.createElement(DockButton, { onClick: this.ideWindow.bind(this), isOpen: this.state.windows.ide }, React.createElement("img", { src: "//repo.bfw.wiki/bfwrepo/icon/5df872a0dab9f.png", style: { height: "55px" } })), React.createElement(DockButton, { onClick: this.fileExplorerWindow.bind(this), isOpen: this.state.windows.fileexplorer }, React.createElement("img", { src: "//repo.bfw.wiki/bfwrepo/icon/5d835147aa4b2.png", style: { height: "55px" } })))))); }} class Window extends React.Component { constructor(props) { super(props); this.state = {}; } render() { // console.log(window.innerHeight, window.innerWidth) let windowStyle = { display: this.props.isHidden ? "none" : "inline-block", minWidth: "40px", minHeight: "20px", position: "absolute", top: Math.min(Math.max(this.props.topPos, 0), window.innerHeight - 20) || 0, left: Math.min(Math.max(this.props.leftPos, 0), window.innerWidth - 40) || 0, zIndex: this.props.layer + 100, transition: "transform .2s linear, opacity .2s linear", transform: `scale(${this.props.closing ? "0.3" : "1"})`, opacity: `${this.props.closing ? "0" : "1"}` }; let headerStyle = { backgroundColor: "rgba(0,0,0,0.9)", userSelect: "none", color: "rgb(75,75,75)", padding: "4px 4px 0px", borderRadius: "5px 5px 0px 0px", height: "20px", ...SANS_FONT }; if (this.props.isHeld) { headerStyle.backgroundColor = "rgba(255,0,0,0.7)"; headerStyle.cursor = "grabbing"; } let closeButtonStyle = { background: "rgba(200, 30, 30, 0.5)" }; let foldButtonStyle = { background: "rgba(150, 150, 30, 0.5)" }; let hideButtonStyle = { background: "rgba(30, 200, 30, 0.5)" }; let bodyStyle = { maxHeight: this.props.isFolded ? "0px" : "", overflow: this.props.isFolded ? "hidden" : "", height: this.props.height || "", width: this.props.width || "" }; return ( React.createElement("div", { style: windowStyle, onMouseDown: this.props.makeActive, onTouchStart: this.props.makeActive, onKeyDown: this.props.onKeyDown }, React.createElement("div", { style: headerStyle, onMouseDown: this.props.grabWindow, onTouchStart: this.props.grabWindow }, this.props.title, React.createElement(WindowHeaderBtn, { style: closeButtonStyle, onMouseDown: this.props.close }), React.createElement(WindowHeaderBtn, { style: foldButtonStyle, onMouseDown: this.props.toggleFold }), React.createElement(WindowHeaderBtn, { style: hideButtonStyle, onMouseDown: this.props.hide })), React.createElement("div", { style: bodyStyle }, this.props.children))); }} class WindowHeaderBtn extends React.Component { constructor(props) { super(props); this.state = {}; } render() { let style = { height: "10px", width: "10px", float: "right", padding: 0, fontSize: "5px", margin: "2px", borderRadius: "10px", background: "rgba(200, 30, 30, 0.7)", cursor: "pointer", ...this.props.style }; return ( React.createElement("div", { style: style, onMouseDown: this.props.onMouseDown, onTouchStart: this.props.onMouseDown })); }} class TerminalWindow extends React.Component { constructor(props) { super(props); this.state = { input: "" }; this.keyPress = function (ev) { if (ev.which == 13 || ev.keyCode == 13) { this.submitInput(); } }; this.submitInput = function () { let input = this.state.input; if (this.props.updateBody) { let newBody = this.props.bodyChunks; newBody.push({ string: " $ ", bold: true, color: 2 }); newBody.push({ string: this.state.input + "\n" }); this.props.updateBody(newBody); } this.setState({ input: "" }); }; } componentDidUpdate(prevProps) { if (this..........完整代码请登录后点击上方下载按钮下载查看
网友评论0