├── public ├── favicon.ico ├── robots.txt ├── manifest.json └── index.html ├── assets └── images │ └── base.png ├── src ├── utils │ ├── cat.js │ └── spotify.js ├── index.js ├── App.js ├── index.css └── components │ ├── Commands │ └── commands.js │ └── Term.js ├── .gitignore ├── .github └── FUNDING.yml ├── package.json ├── LICENSE ├── README.md └── LEARN.md /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asrvd/AshTerm/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /assets/images/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asrvd/AshTerm/HEAD/assets/images/base.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/utils/cat.js: -------------------------------------------------------------------------------- 1 | export default async function getcat() { 2 | const res = await fetch('https://api.thecatapi.com/v1/images/search') 3 | const resp = await res.json() 4 | return resp[0].url 5 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('root') 9 | ); 10 | -------------------------------------------------------------------------------- /src/utils/spotify.js: -------------------------------------------------------------------------------- 1 | export default async function getnp() { 2 | const res = await fetch('https://spotify-np-api.vercel.app/api', {mode: 'cors'}); 3 | console.log(res) 4 | const data = await res.json(); 5 | return data['np']; 6 | } 7 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import Term from './components/Term.js' 3 | 4 | export default function App() { 5 | return ( 6 |
7 | 8 |
9 | ) 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: asheeeshh 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ["https://zink.tips/asheeshh", "https://www.buymeacoffee.com/asheeshh"] 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AshTerm", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.2", 7 | "@testing-library/react": "^12.1.2", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^17.0.2", 10 | "react-console-emulator": "^5.0.1", 11 | "react-dom": "^17.0.2", 12 | "react-hook-figlet": "^1.0.2", 13 | "react-scripts": "5.0.0", 14 | "web-vitals": "^2.1.4" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 ashish 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AshTerm 2 | A Terminal Styled Portfolio Website. 🐱‍💻 3 | 4 | ![Cloudflare](https://img.shields.io/badge/Cloudflare-F38020?style=for-the-badge&logoColor=white&label=Powered%20By) 5 | 6 | ### Made Using- 7 | - ⚛ Framework [ReactJS](https://reactjs.org/) 8 | - 💻 Terminal [react-console-emulator](https://github.com/linuswillner/react-console-emulator) 9 | - 🚀 Deployed using [CloudFlare](https://pages.dev) 10 | 11 | ### Running Locally 🚀 12 | Clone the repos's main branch. 13 | ```sh 14 | $ git clone -b main https://github.com/asheeeshh/AshTerm.git 15 | ``` 16 | Change directory. 17 | ```sh 18 | $ cd AshTerm 19 | ``` 20 | Install dependencies, make sure you have `nodejs` and `npm` installed. 21 | ```sh 22 | $ npm install 23 | ``` 24 | Run the app. 25 | ```sh 26 | $ npm start 27 | ``` 28 | 29 | ### Usage 🐱 30 | Feel free to use this project to make your own Portfolio! Just make sure you give a small credit to my own Project.\ 31 | Cheers! 🍻 32 | 33 | ### Contribution 🤝 34 | Feel free to add Issues/Pull Requests to the Project. 35 | 36 | ### License ⚖ 37 | MIT License 38 | 39 | ### Ending Note ✒ 40 | - *Consider giving the repo a ⭐ if you liked the project!* 41 | - *Follow me and checkout my other projects!* 42 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | AshTerm 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | scroll-behavior: auto; 5 | } 6 | 7 | body { 8 | background-image: url(../assets/images/base.png); 9 | background-repeat: no-repeat; 10 | background-size: cover; 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | height: 100vh; 15 | width: 100vw; 16 | } 17 | 18 | .App { 19 | align-self: center; 20 | height: 95vh; 21 | padding: 5px; 22 | width: 98vw; 23 | background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0)); 24 | backdrop-filter: blur(5px); 25 | -webkit-backdrop-filter: blur(10px); 26 | border-radius: 10px; 27 | border:1px solid rgba(255, 255, 255, 0.18); 28 | box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); 29 | } 30 | 31 | pre { 32 | color: #8be9fd; 33 | padding-left: 20px; 34 | font-size: 14px; 35 | font-weight: bold; 36 | padding-top: 15px; 37 | } 38 | 39 | .head { 40 | color:#ff5555; 41 | font-weight: normal; 42 | } 43 | 44 | .cat { 45 | width: 400px; 46 | height: 300px; 47 | } 48 | 49 | .user-input { 50 | background-color: transparent; 51 | border: none; 52 | outline: none; 53 | color: #ffff; 54 | } 55 | 56 | ::-webkit-scrollbar { 57 | scroll-behavior: auto; 58 | width: 8px; 59 | height:8px; 60 | } 61 | 62 | ::-webkit-scrollbar-track { 63 | background: #6272a4; 64 | background-clip: content-box; 65 | } 66 | 67 | ::-webkit-scrollbar-thumb { 68 | background: #bd93f9; 69 | border-radius: 5px; 70 | } 71 | 72 | ::-webkit-scrollbar-thumb:hover { 73 | background: #bd93f9; 74 | } 75 | 76 | .container { 77 | width: 98vw; 78 | height: 95vh; 79 | padding: 10px 30px 10px 10px; 80 | background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0)); 81 | backdrop-filter: blur(5px); 82 | -webkit-backdrop-filter: blur(10px); 83 | border-radius: 10px; 84 | border:1px solid rgba(255, 255, 255, 0.18); 85 | box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); 86 | border: 1px solid #bd93f9; 87 | } -------------------------------------------------------------------------------- /LEARN.md: -------------------------------------------------------------------------------- 1 | ## AshTerm/Learn 2 | Let's see how you can build the same project from scratch now. 3 | 4 | ### Scaffold the project 5 | Get you code editor and terminal ready, we will need to make a react app first using `create-react-app`. And then we can install the necessary dependencies. We need only one external dependency for this project [react-console-emulator]() 6 | ```bash 7 | npx create-react-app my-app 8 | cd my-app 9 | npm i --legacy-peer-deps react-console-emulator 10 | npm run dev 11 | ``` 12 | Run the above commands one by one in your terminal to create the project and start the app on localhost. Now open the app in a code editor and start coding. 13 | 14 | ### Creating commands for terminal 15 | react-console-emulator provides an easy way to declare commands for your terminal. You can read the full configuration guide [here](https://github.com/linuswillner/react-console-emulator/blob/master/docs/CONFIG.md). 16 | Here's an example app - 17 | ```js 18 | import React, { Component } from 'react' 19 | import Terminal from 'react-console-emulator' 20 | 21 | const commands = { 22 | echo: { 23 | description: 'Echo a passed string.', 24 | usage: 'echo ', 25 | fn: (...args) => args.join(' ') 26 | } 27 | } 28 | 29 | export default class MyTerminal extends Component { 30 | render () { 31 | return ( 32 | 37 | ) 38 | } 39 | } 40 | ``` 41 | paste the code in your main js file and run the app again using `npm run dev`. If you followed correctly you will be seeing a terminal in your app and running the command `echo "hello world"` will print `hello world` in your terminal! 42 | 43 | ### Styling your terminal 44 | Styling the terminal is easy. You can read it [here](https://github.com/linuswillner/react-console-emulator/blob/master/docs/CONFIG.md#re-styling). 45 | 46 | ### Conclusion 47 | This is how you can get started with your terminal styled portfolio project. Feel free to take inspiration from my own portfolio or create your own unique commands! Don't hesitate to ask you questions in Issues. I'll gladly help you out. If you liked the project, consider giving a star to it, my goal is getting 100 stars on this project 😀 48 | -------------------------------------------------------------------------------- /src/components/Commands/commands.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-anonymous-default-export */ 2 | import getcat from "../../utils/cat" 3 | import getnp from "../../utils/spotify" 4 | export default { 5 | commands: { 6 | echo: { 7 | description: 'Prints the given text to the console', 8 | usage: 'echo ', 9 | fn: (...args) => args.join(" ") 10 | }, 11 | // cat: { 12 | // description: 'Get a cute cat image.', 13 | // usage: 'cat', 14 | // fn: async () => { 15 | // const url = await getcat() 16 | // window.open(url, '_blank') 17 | // return "fetching cat...\ncat fetched successfully!" 18 | // } 19 | // }, 20 | about: { 21 | description: 'About Me.', 22 | usage: 'about', 23 | fn: () => { 24 | return "About Me.\n---\nmale\n18\nstudent\nsolodev\nmelophile\nweeb\ndumb\napathetic\n---\n" 25 | } 26 | }, 27 | twitter: { 28 | description: 'Opens my Twitter Handle.', 29 | usage: 'twitter', 30 | fn: () => { 31 | window.open('https://twitter.com/_asheeshh', '_blank') 32 | return "opening twitter handle..." 33 | } 34 | }, 35 | github: { 36 | description: 'Opens my GitHub Profile.', 37 | usage: 'twitter', 38 | fn: () => { 39 | window.open('https://github.com/asrvd', '_blank') 40 | return "opening github account..." 41 | } 42 | }, 43 | discord: { 44 | description: 'Opens my Discord Account.', 45 | usage: 'twitter', 46 | fn: () => { 47 | window.open('https://discordapp.com/users/784363251940458516', '_blank') 48 | return "opening discord account..." 49 | } 50 | }, 51 | languages: { 52 | description: 'Languages I know.', 53 | usage: 'languages', 54 | fn: () => { 55 | return ` 56 | these are the languages I know.\n---\n 57 | english          - 70% 58 | hindi            - 100% 59 | gen-z-langauge   - 00% 60 | python           - 60% 61 | javascript       - 60% 62 | html5            - 90% 63 | css3             - 80% 64 | ruby             - 40% 65 | rust             - 10% - [learning] 66 | go-lang          - 10% - [learning]\n---\n 67 | ` 68 | } 69 | }, 70 | skills: { 71 | description: 'Skills I have.', 72 | usage: 'skills', 73 | fn: () => { 74 | return ` 75 | these are the skills I have.\n---\n 76 | procrastination  - 100% 77 | coding           - 50% 78 | studying         - 10% 79 | overthinking     - 100% 80 | social-skills    - 00% 81 | making-playlists - 100%\n---\n 82 | ` 83 | } 84 | }, 85 | projects: { 86 | description: 'Projects I have worked on.', 87 | usage: 'projects', 88 | fn: () => { 89 | return ` 90 | Cool projects I have worked on.\n---\n 91 | 'ashterm'                         | 'terminal portfolio'   | 'javascript' 92 | 'octocolor'                       | 'github profile color' | 'javascript' 93 | 'kanna-chan'                      | 'Discord-Bot'          | 'python' 94 | 'wordinal'                        | 'wordle-on-terminal'   | 'javascript' 95 | 'weeby.py'                        | 'API-wrapper'          | 'python' 96 | 'gitbanner'                       | 'banner-generator'     | 'javascript'\n---\n 97 | ` 98 | } 99 | }, 100 | editor: { 101 | description: 'Details about my current editor', 102 | usage: 'editor', 103 | fn: () => { 104 | return ` 105 | Editor: Visual Studio Code\n 106 | Theme : Catpuccin\n 107 | Font  : Consolas 108 | ` 109 | } 110 | }, 111 | repo: { 112 | description: "Opens this website's github repository.", 113 | usage: 'repo', 114 | fn: () => { 115 | window.open("https://github.com/asrvd/AshTerm", '_blank') 116 | return "opening repository..." 117 | } 118 | }, 119 | spotify: { 120 | description: 'Get info about my recently played song.', 121 | usage: 'spotify', 122 | fn: async () => { 123 | const item = await getnp() 124 | return ` 125 | Now Playing/Recently Played\n 126 | ---\n 127 | Song: ${item.song}\n 128 | Artist: ${item.artist}\n---\n 129 | ` 130 | } 131 | } 132 | }, 133 | overwrites:{ 134 | help: { 135 | description: 'List all available commands', 136 | usage: 'help', 137 | }, 138 | cd: { 139 | description: 'Change directory, not really, lol!', 140 | usage: 'cd ', 141 | }, 142 | ls: { 143 | description: 'List files in the current directory', 144 | usage: 'ls', 145 | }, 146 | mkdir: { 147 | description: 'Make a directory', 148 | usage: 'mkdir ', 149 | }, 150 | clear: { 151 | description: 'Clears the terminal', 152 | usage: 'clear' 153 | }, 154 | cat: { 155 | description: 'Get a cute cat image.', 156 | usage: 'cat', 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/components/Term.js: -------------------------------------------------------------------------------- 1 | import Terminal from 'react-console-emulator' 2 | import commands from '../components/Commands/commands.js' 3 | import React from 'react' 4 | import figlet from 'figlet'; 5 | import getcat from '../utils/cat' 6 | 7 | export default function Term() { 8 | const cmds = commands.commands 9 | const owrs = commands.overwrites 10 | const terminal = React.createRef() 11 | const [prompt, setPrompt] = React.useState('you@/ashterm:~$ ') 12 | const [home, sethome] = React.useState('ashterm') 13 | const [dir, setdir] = React.useState({ 14 | 'ashterm': [] 15 | }) 16 | return ( 17 | { 34 | terminal.current.clearStdout() 35 | } 36 | }, 37 | cat: { 38 | description: 'Get a random cute cat~', 39 | usage: 'cat', 40 | fn: async () => { 41 | const url = await getcat() 42 | terminal.current.pushToStdout("getting a cute cat for you..\n---\n") 43 | terminal.current.pushToStdout(cat) 44 | } 45 | }, 46 | cd: { 47 | description: 'Change directory, not really, lol!', 48 | usage: 'cd ', 49 | fn: (...args) => { 50 | if (args.length===1 && args[0]==='..') { 51 | if (prompt === 'you@/ashterm:~$ ') { 52 | return 'cannot go up' 53 | } else { 54 | setPrompt(prompt.substring(0, prompt.lastIndexOf('/'))+":~$ ") 55 | sethome(prompt.substring(prompt.lastIndexOf('/', prompt.lastIndexOf('/')-1)+1, prompt.lastIndexOf('/'))) 56 | //console.log(prompt.substring(prompt.lastIndexOf('/', prompt.lastIndexOf('/')-1)+1, prompt.lastIndexOf('/'))) 57 | //console.log(prompt.lastIndexOf('/', prompt.lastIndexOf('/')-1)) 58 | //console.log(prompt.lastIndexOf('/')) 59 | return 'changed directory' 60 | } 61 | } else { 62 | if (dir[home].includes(args[0])) { 63 | setPrompt(`${prompt.slice(0, -4)+ "/" + args.join('/') + ":~$ "}`) 64 | sethome(args.join('/')) 65 | //console.log(prompt.slice(0, -4)+ "/" + args.join('/')) 66 | return 'changed directory' 67 | } else { 68 | return 'cannot find directory' 69 | } 70 | } 71 | 72 | } 73 | }, 74 | ls: { 75 | description: 'List files in the current directory', 76 | usage: 'ls', 77 | fn: () => { 78 | if (dir[home].length === 0) { 79 | return 'nothing here :(\nUse mkdir to create a dir inside this one.' 80 | } else { 81 | return dir[home].join('\n') 82 | } 83 | } 84 | 85 | }, 86 | mkdir: { 87 | description: 'Make a directory', 88 | usage: 'mkdir ', 89 | fn: (...args) => { 90 | if (args.length===1) { 91 | setdir({ 92 | ...dir, 93 | [home]: [...dir[home], args[0]], 94 | [args[0]]:[] 95 | }) 96 | //console.log(dir) 97 | return `created directory ${args[0]}.` 98 | } else { 99 | return 'invalid arguments' 100 | } 101 | } 102 | }, 103 | help: { 104 | description: 'List all available commands', 105 | usage: 'help', 106 | fn: () => { 107 | return ` 108 | ${Object.keys(owrs).map(cmd => `${cmd}${" ".repeat(12-cmd.length)} | ${owrs[cmd].description}${" ".repeat(39-owrs[cmd].description.length)} | ${owrs[cmd].usage}`).join('\n')} 109 | ${Object.keys(cmds).map(cmd => `${cmd}${" ".repeat(12-cmd.length)} | ${cmds[cmd].description}${" ".repeat(39-cmds[cmd].description.length)} | ${cmds[cmd].usage}`).join('\n')} 110 | ` 111 | } 112 | }, 113 | ...cmds 114 | }} 115 | promptLabel={prompt} 116 | autoFocus 117 | style={{ 118 | backgroundColor:null, 119 | minHeight: null, 120 | maxHeight: null, 121 | overflow: 'auto', 122 | height: '100%', 123 | width: '100%', 124 | }} 125 | styleEchoBack='fullInherit' 126 | contentStyle={{ color: '#ffb86c' , fontWeight: 'normal', paddingLeft: null}} // Text colour 127 | promptLabelStyle={{ color: '#ff5555' , fontWeight:'normal'}} // Prompt label colour 128 | inputTextStyle={{ color: '#f1fa8c' , fontWeight: 'normal'}} 129 | messageStyle={{ color: '#8be9fd' , fontWeight: 'normal', paddingLeft: null}} 130 | scrollBehavior='auto' 131 | noDefaults 132 | /> 133 | ) 134 | } --------------------------------------------------------------------------------