1
0
Fork 0
mirror of https://github.com/dilllxd/gitfolio.git synced 2024-08-14 22:28:09 +00:00

Compare commits

..

No commits in common. "master" and "v0.1.2" have entirely different histories.

37 changed files with 2763 additions and 9396 deletions

View file

@ -1,17 +0,0 @@
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"rules": {}
}

5
.gitattributes vendored
View file

@ -1,5 +0,0 @@
# Set the default behavior, in case people don't have core.autocrlf set
* text=auto
# Require Unix line endings
* text eol=lf

View file

@ -5,8 +5,8 @@ about: Request a new feature.
# What feature should be added?
This feature adds Twitter, Linkedin and Medium links to your profile.
<!-- Explain what the feature is here -->
# Why should this feature be added?
Since a portfolio is being made, adding these links help improve the profile better.
<!-- Provide information on what improvements this feature brings -->

3
.gitignore vendored
View file

@ -64,5 +64,4 @@ typings/
dist/
# Editor files and folders
.vscode/
.idea/
.vscode/

View file

@ -1,17 +0,0 @@
{
"overrides": [
{
"files": ["*.html", "*.ejs"],
"options": {
"parser": "html",
"htmlWhitespaceSensitivity": "ignore"
}
},
{
"files": "*.md",
"options": {
"tabWidth": 4
}
}
]
}

4
.snyk
View file

@ -1,4 +0,0 @@
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
version: v1.13.5
ignore: {}
patch: {}

View file

@ -1,3 +0,0 @@
{
"extends": ["stylelint-config-standard", "stylelint-prettier/recommended"]
}

View file

@ -1,26 +0,0 @@
dist: bionic
language: node_js
node_js:
- 11
addons:
chrome: stable
cache:
directories:
- node_modules
before_install:
- npm install -g @lhci/cli@0.3.x
before_script:
- npm install -g
script:
- npm run build
- npm run prettier
after_success:
- lhci autorun --upload.target=temporary-public-storage
deploy:
provider: pages
token: $GITHUB_TOKEN
cleanup: false
edge: true # opt in to dpl v2
local_dir: dist
verbose: true
fqdn: dylanh.dev # forcing run

View file

@ -1,76 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at imfunny@wybemf.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
<https://www.contributor-covenant.org/faq>
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at imfunny@wybemf.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

1348
LICENSE

File diff suppressed because it is too large Load diff

321
README.md
View file

@ -1,175 +1,146 @@
[![Build Status](https://travis-ci.com/dilllxd/gitfolio.svg?branch=master)](https://travis-ci.com/dilllxd/gitfolio)
[![Code Style: Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?logo=prettier&style=for-the-badge)](https://github.com/prettier/prettier)
[![GitHub release](https://img.shields.io/github/release/imfunniee/gitfolio.svg?style=for-the-badge)](https://github.com/imfunniee/gitfolio/releases/latest)
# Gitfolio
### personal website + blog for every github user
Gitfolio will help you get started with a portfolio website where you could showcase your work + a blog that will help you spread your ideas into real world.
<img src="https://i.imgur.com/eA6clZr.png">
---
Check out this [live demo](https://k4ustu3h.cf) to see gitfolio in action.
---
# Getting Started
### Let's Install
Install gitfolio
```sh
➜ ~ git clone https://github.com/k4ustu3h/gitfolio.git
➜ ~ cd gitfolio
➜ ~ npm install -g
```
### Let's Build
Using the UI
```sh
➜ ~ gitfolio ui
```
> Tip: You can use ui to create new blogs and for updating your folio too.
or
```sh
➜ ~ gitfolio build <username>
```
`<username>` is your username on github. This will build your website using your GitHub username and put it in the `/dist` folder.
To run your website use `run` command, Default port is 3000
```sh
➜ ~ gitfolio run -p [port]
```
🎉 Congrats, you just made yourself a personal website!
---
### Let's Customize
#### Forks
To include forks on your personal website just provide `-f` or `--fork` argument while building
```sh
➜ ~ gitfolio build <username> -f
```
#### Sorting Repos
To sort repos provide `--sort [sortBy]` argument while building. Where `[sortBy]` can be `star`, `created`, `updated`, `pushed`,`full_name`. Default: `created`
```sh
➜ ~ gitfolio build <username> --sort star
```
#### Ordering Repos
To order the sorted repos provide `--order [orderBy]` argument while building. Where `[orderBy]` can be `asc` or `desc`. Default: `asc`
```sh
➜ ~ gitfolio build <username> --sort star --order desc
```
#### Customize Themes
Themes are specified using the `--theme [theme-name]` flag when running the `build` command. The available themes are
- `light`
- `dark`
> TODO: Add more themes
For example, the following command will build the website with the dark theme
```sh
➜ ~ gitfolio build <username> --theme dark
```
#### Customize background image
To customize the background image just provide `--background [url]` argument while building
```sh
➜ ~ gitfolio build <username> --background https://images.unsplash.com/photo-1557277770-baf0ca74f908?w=1634
```
You could also add in your custom CSS inside `index.css` to give it a more personal feel.
#### Add Social Media links on your profile
gitfolio supports adding the follwing Social links
- Codepen `-c, --codepen <username>`
- Dev.to `-d, --dev <username>`
- Dribbble `-D, --dribbble <username>`
- Email `-e, --email <email>`
- Facebook `-F, --facebook <username>`
- Instagram `-i, --instagram <username>`
- Keybase `-k, --keybase <username>`
- Medium `-m, --medium <username>`
- Reddit `-r, --reddit <username>`
- Stack Exchange `-E, --stackexchange <user id>`
- Steam `-S, --steam <username>`
- Telegram `-T, --telegram <username>`
- Twitter `-w, --twitter <username>`
- XDA Developers `-x, --xda <user id>`
```sh
➜ ~ gitfolio build <username> --twitter <twitter_username> --dribbble <dribbble_username>
```
---
### Let's Publish
Head over to GitHub and create a new repository named `username.github.io`, where username is your username. Push the files inside`/dist` folder to repo you just created.
Go To `username.github.io` your site should be up!!
---
### Updating
To update your info, simply run
```sh
➜ ~ gitfolio update
```
or use the `Update` options in gitfolio's UI
This will update your info and your repository info.
To Update background or theme you need to run `build` command again.
---
### License
[![License](https://img.shields.io/github/license/k4ustu3h/gitfolio.svg?style=for-the-badge)](https://github.com/k4ustu3h/gitfolio/blob/master/LICENSE)
---
## Acknowledgments
- Hat tip to anyone who's code was used
- The original [gitfolio](https://github.com/imfunniee/gitfolio) made by [@imfunniee](https://github.com/imfunniee/)
---
[![CSS](https://img.shields.io/badge/uses-css-1572B6?logo=css3&style=for-the-badge)](https://github.com/topics/css)
[![h9rbs.js](https://img.shields.io/badge/uses-h9rbs.js-473349?style=for-the-badge)](https://html9responsiveboilerstrapjs.com/)
[![HTML](https://img.shields.io/badge/uses-html-E34F26?logo=html5&style=for-the-badge)](https://github.com/topics/html)
[![JavaScript](https://img.shields.io/badge/made_with-javascript-F7DF1E?logo=javascript&style=for-the-badge)](https://github.com/topics/javascript)
<img src="https://i.imgur.com/eA6clZr.png">
# Gitfolio [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=personal%20website%20and%20a%20blog%20for%20every%20github%20user%20&url=https://github.com/imfunniee/gitfolio) ![GitHub release](https://img.shields.io/github/release/imfunniee/gitfolio.svg) ![GitHub top language](https://img.shields.io/github/languages/top/imfunniee/gitfolio.svg) ![GitHub last commit](https://img.shields.io/github/last-commit/imfunniee/gitfolio.svg) ![GitHub](https://img.shields.io/github/license/imfunniee/gitfolio.svg)
### personal website + blog for every github user
Gitfolio will help you get started with a portfolio website where you could showcase your work + a blog that will help you spread your ideas into real world.
Check out this [live demo](https://imfunniee.github.io/gitfolio/) to see gitfolio in action.
# Getting Started
### Let's Build
a. Clone this repo or simply download it.
```sh
git clone https://github.com/imfunniee/gitfolio.git
```
b. `cd` into the repo you just cloned or downloaded.
```sh
cd gitfolio # Navigate into the project folder
npm i # Install the required dependencies
```
c. Gitfolio is now ready to be used. The command
```sh
node build --name [username]
```
Will build your website using your GitHub username and put it in the `dist/` folder.
d. To run your website navigate to `./dist/index.html` in your browser. [you won't see blogs until you are on localhost]
🎉 Congrats, you just made yourself a personal website!
> if you get stuck somewhere or get an error, please create an issue
### Let's Customize
#### Forks
To include forks on your personal website just provide `-f` or `--fork` argument while building
```
$ node build --name username -f
```
#### Sorting Repos
To sort repos provide `--sort [sortBy]` argument while building. Where `[sort]` can be `created`, `updated`, `pushed`,`full_name`. Default: `created`
```
$ node build --name username --sort created
```
#### Ordering Repos
To order the sorted repos provide `--order [orderBy]` argument while building. Where `[orderBy]` can be `asc` or `desc`. Default: `asc`
```
$ node build --name username --sort created --order desc
```
#### Customize Themes
Themes are specified using the `--theme [theme-name]` flag when running the `build` command. The available themes are
* `light`
* `dark`
> TODO: Add more themes
For example, the following command will build the website with the dark theme
```
$ node build --name username --theme dark
```
#### Customize background image
To customize the background image just provide `--background [url]` argument while building
```
$ node build --name username --background https://images.unsplash.com/photo-1557277770-baf0ca74f908?w=1634
```
You could also add in your custom CSS inside `index.css` to give it a more personal feel.
### Let's Publish
Head over to GitHub and create a new repository named `username.github.io`, where username is your username. Push the files inside`/dist` folder to repo you just created.
Go To `username.github.io` your site should be up!!
### Updating
To update your info, simply run
```
$ node update
```
This will update your info and your repository info.
To Update background or theme you need to run `build` command again.
### Add a Blog
To add your first blog run this command, make sure the title don't have spaces instead use "-".
```
$ node blog --title my-first-blog
```
This will create a `my-first-blog` folder inside `blog`. Inside `my-first-blog` you will find an `index.html` file which contains all the necessary elements for writing a blog. Customize the content of the file to write your first blog.
This also adds content to `blog.json` file. This file helps in showcasing your blogs on your personal website as [cards](https://imfunniee.github.io/gitfolio/#blog_section). You could customize the JSON object that corresponds your current blog.
Blog Demo? [here](https://imfunniee.github.io/gitfolio/blog/my-first-blog/)
Default JSON Format
```
{
"url_title": "my-first-blog", // the title you provide while creating a new blog, this appears in url
"title": "Lorem ipsum dolor sit amet", // main title of blog
"sub_title": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", // sub-title of blog
"top_image": "https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450", // main image of blog
"visible": true // don't worry about this
}
```
More Arguments for Blog
```
--subtitle [subtitle] : gives blog a subtitle (Deafult : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
--pagetitle [pagetitle] : gives blog page a title
--folder [folder] : give folder a title
```
> (use "-" instead of spaces)
## License
![GitHub](https://img.shields.io/github/license/imfunniee/gitfolio.svg)

67
api.js
View file

@ -1,67 +0,0 @@
const got = require("got");
/**
* The defaults here are the same as the API
* @see https://developer.github.com/v3/repos/#list-user-repositories
* @param {string} username
* @param {Object} opts
* @param {('all' | 'owner' | 'member')[]} [opts.types]
* @param {'created' | 'updated' | 'pushed' | 'full_name' | 'star'} [opts.sort]
* @param {'desc' | 'asc'} [opts.order]
*/
async function getRepos(username, opts = {}) {
let tempRepos;
let page = 1;
let repos = [];
const { sort } = opts;
const order = opts.order || (sort === "full_name" ? "asc" : "desc");
const types = opts.types || [];
let type = "all";
if (
types.includes("all") ||
(types.includes("owner") && types.includes("member"))
) {
type = "all";
} else if (types.includes("member")) {
type = "member";
}
do {
let requestUrl = `https://api.github.com/users/${username}/repos?per_page=100&page=${page++}&type=${type}`;
if (sort && sort !== "star") {
requestUrl += `&sort=${sort}&direction=${order}`;
}
tempRepos = await got(requestUrl);
tempRepos = JSON.parse(tempRepos.body);
repos = repos.concat(tempRepos);
} while (tempRepos.length === 100);
if (sort === "star") {
repos = repos.sort((a, b) => {
if (order === "desc") {
return b.stargazers_count - a.stargazers_count;
}
return a.stargazers_count - b.stargazers_count;
});
}
return repos;
}
/**
* @see https://developer.github.com/v3/users/#get-a-single-user
* @param {string} username
*/
async function getUser(username) {
const res = await got(`https://api.github.com/users/${username}`);
return JSON.parse(res.body);
}
module.exports = {
getRepos,
getUser
};

9
assets/blog/blog.json Normal file
View file

@ -0,0 +1,9 @@
[
{
"url_title": "FooBar",
"title": "FooBar",
"sub_title": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"top_image": "https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450",
"visible": true
}
]

View file

@ -0,0 +1,64 @@
<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Lorem ipsum dolor</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
</head>
<body>
<div id="loading">
<div id="spinner"></div>
</div>
<a href="/" class="go_back"><i class="fas fa-arrow-left"></i></a>
<div id="background"></div>
<table id="profile_blog">
<tbody><tr>
<td style="width:8vw;"><div id="profile_img_blog"></div></td>
<td style="width:52vw;">
<div id="username_blog"></div>
</td>
</tr>
</tbody></table>
<div id="blog-display">
<h1 id="blog_title">Lorem ipsum dolor</h1>
<h2 id="blog_sub_title">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
<div id="blog">
<img src="https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut placerat pretium sem, ac maximus dui sodales a. Nunc aliquet hendrerit turpis ac egestas. Phasellus volutpat tristique maximus. <b>Pellentesque feugiat eget nisi et dignissim.</b> Nam nibh erat, sollicitudin non facilisis nec, scelerisque nec ipsum. Sed accumsan velit condimentum, pharetra felis vitae, commodo tellus. <u><i>Mauris consequat luctus orci.</i></u></p>
<p>
Vivamus pharetra lobortis dui non tincidunt. Mauris vitae nisi vestibulum, mollis magna a, maximus mi. Suspendisse dictum eget augue quis sodales. Quisque rutrum ligula nec dapibus tincidunt. <span>Proin hendrerit massa a tellus vestibulum, a hendrerit ipsum iaculis. Suspendisse potenti.</span> Praesent eget erat blandit, finibus sapien vitae, ullamcorper erat. Integer blandit, felis at ullamcorper maximus, odio lectus pretium mauris, vel consequat lectus quam eu risus. Pellentesque gravida nec diam eget vehicula.
</p>
<img src="https://images.unsplash.com/photo-1556814278-8906c7d3a05f?w=1050">
<p>
Donec hendrerit turpis non libero eleifend dignissim. Mauris non tempor metus, et tristique massa. Integer consequat justo quam, vitae aliquam arcu vestibulum at. Donec porttitor quam in tempus convallis. Praesent feugiat eget eros vitae accumsan. Duis ultricies odio quis nisl volutpat, consectetur imperdiet sem laoreet. Quisque maximus semper ligula at tincidunt. Pellentesque accumsan varius vehicula.
</p>
</div>
</div>
<div id="footer_blog">
<a href="https://github.com/imfunniee" target="_blank">made on earth by a human</a>
</div>
<script type="text/javascript">
setTimeout(function(){
document.getElementById("loading").classList.add("animated");
document.getElementById("loading").classList.add("fadeOut");
setTimeout(function(){
document.getElementById("loading").classList.remove("animated");
document.getElementById("loading").classList.remove("fadeOut");
document.getElementById("loading").style.display = "none";
},800);
},1500);
$.getJSON("../../config.json", function(user){
var icon = document.createElement("link");
icon.setAttribute("rel", "icon");
icon.setAttribute("href", user[0].userimg);
icon.setAttribute("type", "image/png");
document.getElementsByTagName("head")[0].appendChild(icon);
document.getElementById("profile_img_blog").style.background = `url('${user[0].userimg}') center center`;
document.getElementById("username_blog").innerHTML = `<spanstyle="display:${user[0].name == null || !user[0].name ? 'none' : 'block'};">${user[0].name}</span><br>@${user[0].username}<b id="blog_time"></b>`;
});
</script>
</body></html>

Binary file not shown.

Binary file not shown.

View file

@ -1,349 +1,433 @@
@charset "UTF-8";
@font-face {
font-family: "Manrope VF";
src: url("/assets/fonts/variable/Manrope%5Bwght%5D.ttf")
format("truetype-variations");
font-style: normal;
font-weight: 200 800;
}
@font-face {
font-family: "Manrope";
src: url("/assets/fonts/web/manrope-bold.woff2") format("woff2"),
url("/assets/fonts/otf/manrope-bold.otf") format("opentype");
font-style: normal;
font-weight: 700;
}
body {
align-items: center;
background: var(--bg-color);
color: var(--text-color);
font-family: "Manrope VF", Manrope, sans-serif;
font-feature-settings: "calt", "liga";
font-size: 64px;
font-variation-ligatures: normal;
font-variation-settings: "wght" 500;
font-weight: 700;
margin: 0%;
max-width: 100vw;
overflow-x: hidden;
padding: 0%;
width: 100vw;
}
.profile {
background: var(--background-image) center center;
background-repeat: no-repeat;
background-size: cover !important;
color: #fff !important;
display: flex;
flex-direction: column;
height: 92vh;
justify-content: center;
padding: 4vh 3vw;
position: fixed;
text-align: left;
width: 24vw;
}
.display {
display: inline-block;
height: 92vh;
padding: 4vh 3vw;
padding-left: 33vw;
width: 64vw;
}
.display h1 {
color: var(--text-color);
font-family: "Asap", sans-serif;
font-size: 50px;
font-weight: bold;
}
.emoji {
height: 18px;
width: 18px;
}
.footer {
padding: 8vh 0;
text-align: center;
width: 100%;
}
.footer a {
color: var(--text-color) !important;
font-family: "Manrope VF", Manrope, sans-serif;
font-feature-settings: "calt", "liga";
font-variation-ligatures: normal;
font-variation-settings: "wght" 500;
font-weight: 700;
text-decoration: none;
}
#profile_img {
width: 180px;
height: 180px;
min-width: 180px;
min-height: 180px;
max-width: 180px;
max-height: 180px;
border-radius: 5px;
background-size: cover !important;
background-repeat: no-repeat !important;
}
@keyframes grad {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.profile div {
font-weight: bold;
margin: 1.5vh 0;
}
.hidden {
opacity: 0;
}
#username {
color: white;
font-family: "Asap Condensed", sans-serif;
font-size: 18px;
}
.bottom_section span {
font-weight: bold;
margin-right: 20px;
}
.socials span {
display: inline-block !important;
font-weight: normal !important;
margin-right: 2vw !important;
}
#username span {
font-family: "Asap Condensed", sans-serif;
font-size: 24px;
}
.console-underscore {
display: inline-block;
left: 10px;
position: relative;
top: -0.14em;
}
#userbio {
font-family: "Asap", sans-serif;
font-size: 26px;
width: 100%;
}
#about {
font-family: "Asap", sans-serif;
font-size: 18px;
}
.projects a {
display: flex;
text-decoration: none;
/* 30px is the gutter size in magic grid */
width: calc(49% - 30px);
/* 49% avoids a weird single column on some wide screens */
}
.socials span a {
font-weight: normal !important;
}
#about a,
#username a {
color: #fff !important;
font-weight: bold;
text-decoration: none;
}
#about a:hover,
#username a:hover {
text-decoration: underline;
}
#about span {
display: block;
margin: 1vh 0;
}
.bottom_section span i {
font-size: 15px;
}
#about span i {
font-size: 16px;
}
#work {
margin: 2vh 0;
padding: 4vh 0 !important;
}
#forks {
margin: 2vh 0;
padding: 4vh 0 !important;
}
.projects {
margin-left: -15px;
/* align section w/ heading above */
}
.projects section {
border: 1px solid rgb(0, 0, 0, 0.08);
border-radius: 5px;
box-shadow: 0 0 0 rgb(0, 0, 0, 0);
color: var(--text-color);
display: inline-block;
margin: 1vh 0;
padding: 2.5vh 5%;
transform: scale(1);
transition: 0.4s ease-in-out;
width: 100%;
}
.projects section:hover {
border: 1px solid rgb(0, 0, 0, 0);
box-shadow: 0 15px 35px rgb(0, 0, 0, 0.06);
cursor: pointer;
transform: scale(1.03);
}
.section_title {
font-size: 24px;
font-weight: bold;
margin: 1vh 0;
padding: 0 1px;
word-wrap: break-word;
}
.about_section {
font-family: "Asap", sans-serif;
font-size: 18px;
font-weight: bold;
margin: 2vh 0;
word-wrap: break-word;
}
.bottom_section {
font-size: 14px;
margin: 1vh 0;
word-wrap: break-word;
}
.socials {
color: #fff;
margin: 3vh 0 !important;
text-decoration: none;
}
::selection {
background: var(--text-color);
color: var(--bg-color);
}
@media (max-width: 800px) {
.profile {
height: 60vh;
padding: 4vh 5vw;
position: relative;
text-align: center;
width: 90vw;
}
.display {
display: inline-block;
height: auto;
padding: 4vh 5vw;
padding-left: 5vw;
width: 90vw;
}
.profile_img {
animation: grad 8s ease infinite;
background: var(--gradient);
background-size: 300% 300%;
font-family: "Asap Condensed", sans-serif;
font-size: 128px;
margin: 0 auto !important;
transition: background 0.5s ease;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
@keyframes grad {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
#work {
margin: 0;
}
.projects {
margin-left: 0;
/* remove neg margin to align w/ header */
}
.projects a {
width: 100%;
}
.projects section {
width: 88%;
}
}
::-webkit-scrollbar {
height: 5px;
width: 5px;
}
::-webkit-scrollbar-track {
background: var(--bg-color);
}
::-webkit-scrollbar-thumb {
background: var(--text-color);
}
/* Iconify */
.iconify {
font-size: 24px;
line-height: 14px;
}
@import url('https://fonts.googleapis.com/css?family=Poppins');
@import url('https://fonts.googleapis.com/css?family=Questrial');
body{
margin:0%;
padding:0%;
width:100vw;
background:var(--bg-color);
color:var(--text-color);
max-width:100vw;
overflow-x:hidden;
align-items:center;
font-family: 'Poppins', sans-serif;
}
#loading {
width: 100vw;
height: 100vh;
position: fixed;
background: var(--bg-color);
z-index: 999;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
top:0;
bottom:0;
left:0;
right:0;
}
#spinner {
animation: rotate 0.5s infinite linear;
width:50px;
height:50px;
border:2px solid var(--bg-color);
border-bottom:2px solid var(--text-color);
border-radius:50%;
margin:0;
}
@keyframes rotate {
0% {transform: rotate(0deg);}
100% {transform: rotate(360deg);}
}
#profile {
width:24vw;
padding:4vh 3vw;
height:92vh;
display:flex;
flex-direction:column;
justify-content:center;
text-align:left;
background:var(--background-image) center center;
background-size: cover !important;
background-repeat:no-repeat;
position:fixed;
color:#fff !important;
}
#display {
width:64vw;
padding:4vh 3vw;
height:92vh;
display:inline-block;
padding-left:33vw;
}
#display h1 {
font-size:50px;
color:var(--text-color);
font-weight:bold;
font-family: 'Questrial', sans-serif;
}
.emoji {
width:18px;
height:18px;
}
#profile_img_blog {
border-radius:50%;
width:90px;
height:90px;
background-size:cover !important;
background-repeat: no-repeat;
}
#username_blog {
font-size:18px;
color:var(--text-color);
font-family: 'Poppins', sans-serif;
font-weight:bold;
}
#username_blog span {
font-size:24px;
font-family: 'Questrial', sans-serif !important;
}
#username_blog b {
font-size:12px;
font-family:'Poppins', sans-serif;
font-weight:bold;
}
#blog-display {
width:60vw;
margin:0px 20vw;
text-align:left;
margin-top:3vh;
z-index:1;
}
#profile_blog {
width:60vw;
margin:0px 20vw;
margin-top:10vh;
text-align:left;
z-index:1;
}
#background {
width:100vw;
height:55vh;
background:var(--background-background);
background-size:cover !important;
background-repeat:no-repeat;
position: absolute;
z-index:-1;
margin-top:-10vh;
}
#blog-display h1 {
font-size:50px;
color:var(--text-color);
font-weight:bold;
font-family: 'Questrial', sans-serif;
}
#blog-display h2 {
color:var(--blog-gray-color);
}
#blog-display {
padding:1vh 0px;
font-family: 'Questrial', sans-serif;
}
#blog p {
font-size:17px;
line-height:25px;
word-spacing:1.2px;
margin:5vh 0px;
}
#blog p span {
padding:2px 4px;
background:var(--text-color);
color:var(--bg-color) !important;
}
#blog img {
width:100%;
margin:2vh 0px;
border-radius:5px;
border:1px solid rgb(0, 0, 0, 0.08);
}
#header {
width:63vw;
text-align:right;
padding:3vh 0px;
position:absolute;
}
#header a {
color:var(--text-color);
text-decoration:none;
margin-left:4vw;
font-weight:bold;
}
#footer_blog {
width:90vw;
padding:8vh 5vw;
text-align:center;
}
#footer_blog a {
color:var(--text-color) !important;
text-decoration:none;
font-family: 'Questrial', sans-serif;
font-weight:bold;
}
#footer {
width:100%;
padding:8vh 0px;
text-align:center;
}
#footer a {
color:var(--text-color) !important;
text-decoration:none;
font-family: 'Questrial', sans-serif;
font-weight:bold;
}
#profile_img {
width:180px;
height:180px;
border-radius:5px;
background-size:cover !important;
}
#profile div {
font-weight:bold;
margin:1.5vh 0px;
}
#username {
font-size:18px;
font-weight:bold;
}
#username span {
font-size:24px;
}
#userbio {
font-size:26px;
font-family: 'Questrial', sans-serif;
width:100%;
}
#about {
font-size:18px;
font-family: 'Questrial', sans-serif;
}
#about span {
margin:1vh 0px;
display:block;
}
#about span i {
font-size:16px;
}
#work {
margin:2vh 0px;
padding:4vh 0px !important;
}
#forks {
margin:2vh 0px;
padding:4vh 0px !important;
}
.projects {
columns:2;
}
.projects section {
width:85%;
padding:2.5vh 5%;
display:inline-block;
border-radius:5px;
color:var(--text-color);
border:1px solid rgb(0, 0, 0, 0.08);
box-shadow:0px 0px 0px rgb(0, 0, 0, 0);
transition:0.4s ease-in-out;
margin:2vh 0px;
transform:scale(1);
}
.projects section:hover {
cursor: pointer;
border:1px solid rgb(0, 0, 0, 0);
box-shadow:0px 15px 35px rgb(0, 0, 0, 0.06);
transform:scale(1.03);
}
.section_title {
font-size:24px;
font-weight:bold;
margin:1vh 0px;
}
.about_section {
font-size:18px;
font-family: 'Questrial', sans-serif;
margin:2vh 0px;
font-weight:bold;
}
.bottom_section {
margin:1vh 0px;
font-size:14px;
}
.bottom_section span {
margin-right:20px;
font-weight:bold;
}
.bottom_section span i {
font-size:15px;
}
#blog_section {
margin:2vh 0px;
padding:2vh 0px !important;
}
#blogs {
columns:2;
}
#blogs section {
width:85%;
display:inline-block;
border-radius:5px;
color:var(--text-color);
border:1px solid rgb(0, 0, 0, 0.04);
box-shadow:0px 0px 0px rgb(0, 0, 0, 0);
transition:0.4s ease-in-out;
transform:scale(1);
padding:0px;
margin:2vh 0px;
}
#blogs section img {
width:100%;
border-radius:5px 5px 0px 0px;
}
.blog_container {
padding:2.5vh 5%;
}
#blogs section:hover {
cursor: pointer;
border:1px solid rgb(0, 0, 0, 0);
box-shadow:0px 15px 35px rgb(0, 0, 0, 0.06);
transform:scale(1.03);
}
.go_back {
position: absolute;
color:var(--text-color);
font-size:26px;
margin-left:5vw;
margin-top:4vh;
}
::selection {
color:var(--bg-color);
background:var(--text-color);
}
@media (max-width: 800px){
#profile {
width:90vw;
padding:4vh 5vw;
height:60vh;
text-align:center;
position: relative;
}
#display {
width:90vw;
padding:4vh 5vw;
height:auto;
display:inline-block;
padding-left:5vw;
}
#profile_img {
width:120px;
height:120px;
margin:0px auto !important;
}
#work {
margin:0px;
}
#projects {
columns:1;
}
#projects section {
width:88%;
}
#blogs {
columns:1;
}
#blogs section {
width:98%;
}
#blog_section {
margin:0px;
}
#blog-display {
width:90vw;
margin:0px 5vw;
text-align:left;
margin-top:0vh;
z-index:1;
}
#profile_blog {
width:90vw;
margin:0px 5vw;
margin-top:10vh;
text-align:left;
z-index:1;
}
.go_back {
position: relative;
color:var(--text-color);
font-size:26px;
margin-left:5vw;
top:5vh;
}
#blog img {
margin:1vh 0px !important;
}
#blog p {
margin:2vh 0px;
}
}
::-webkit-scrollbar {width:5px;height:5px;}
::-webkit-scrollbar-track {background:var(--bg-color);}
::-webkit-scrollbar-thumb {background:var(--text-color);}

View file

@ -1,50 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title></title>
<link
href="https://fonts.googleapis.com/css?family=Asap|Asap+Condensed&display=swap"
rel="stylesheet"
/>
<script src="https://unpkg.com/magic-grid/dist/magic-grid.min.js"></script>
<script src="https://code.iconify.design/1/1.0.6/iconify.min.js"></script>
<script
src="https://code.jquery.com/jquery-3.5.0.min.js"
integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ="
crossorigin="anonymous"
></script>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="profile">
<div id="profile_img"></div>
<div id="username">
<div id="fullname"></div>
</div>
<div id="about"></div>
</div>
<div class="display">
<div id="work">
<h1>Work.</h1>
<div class="projects" id="work_section"></div>
</div>
<div id="forks" style="display: none;">
<h1>Forks.</h1>
<div class="projects" id="forks_section"></div>
</div>
<div class="footer">
<a
href="https://github.com/dilllxd/gitfolio#acknowledgments"
target="_blank"
>
made on earth by humans
</a>
</div>
</div>
<div id="script"></div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="loading">
<div id="spinner"></div>
</div>
<div id="profile">
<div id="profile_img"></div>
<div id="username">
<div id="fullname"></div>
</div>
<div id="userbio"></div>
<div id="about"></div>
</div>
<div id="display">
<div id="work">
<h1>Work.</h1>
<div class="projects" id="work_section"></div>
</div>
<div id="forks" style="display:none;">
<h1>Forks.</h1>
<div class="projects" id="forks_section"></div>
</div>
<div id="blog_section">
<h1>Blog.</h1>
<div id="blogs"></div>
</div>
<div id="footer">
<a href="https://github.com/imfunniee" target="_blank">made on earth by a human</a>
</div>
</div>
<script type="text/javascript">
setTimeout(function(){
document.getElementById("loading").classList.add("animated");
document.getElementById("loading").classList.add("fadeOut");
setTimeout(function(){
document.getElementById("loading").classList.remove("animated");
document.getElementById("loading").classList.remove("fadeOut");
document.getElementById("loading").style.display = "none";
},800);
},1500);
$.getJSON("blog.json", function(blog){
if(blog.length == 0){
return document.getElementById("blog_section").style.display = "none";
}
for(var i = 0; i < blog.length; i++){
$("#blogs").append(`
<a href="./blog/${blog[i].url_title}/" target="_blank">
<section>
<img src="${blog[i].top_image}">
<div class="blog_container">
<div class="section_title">${blog[i].title}</div>
<div class="about_section">
${blog[i].sub_title}
</div>
</div>
</section>
</a>
`);
}
});
</script>
</body>
</html>

View file

@ -1,39 +1,31 @@
:root {
--bg-color: rgb(10, 10, 10);
--text-color: #fff;
--background-image: linear-gradient(
90deg,
rgba(10, 10, 10, 0.3),
rgb(10, 10, 10, 1)
),
url("{{{background}}}");
--background-background: linear-gradient(
0deg,
rgba(10, 10, 10, 1),
rgba(10, 10, 10, 0.6)
),
url("{{{background}}}") center center fixed;
--height: 50vh;
--gradient: linear-gradient(90deg, #009bef, #f00);
}
#display h1 {
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: #fff;
}
.projects section {
background: rgb(20, 20, 20);
}
@media (max-width: 800px) {
:root {
--background-image: linear-gradient(
0deg,
rgba(10, 10, 10, 1),
rgba(10, 10, 10, 0)
),
url("{{{background}}}") !important;
}
}
:root {
--bg-color: rgb(10, 10, 10);
--text-color: #fff;
--blog-gray-color: rgb(180, 180, 180);
--background-image: linear-gradient(90deg, rgba(10, 10, 10, 0.6), rgb(10, 10, 10, 1)), url("{{background}}");
--background-background: linear-gradient(0deg, rgba(10, 10, 10, 1), rgba(10, 10, 10, 0.6)),
url("{{background-image}}") center center fixed;
--height: 50vh;
}
#display h1 {
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: #fff;
}
#blog-display h1 {
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: #fff;
}
.projects section {
background: rgb(20, 20, 20);
}
#blog_section section {
background: rgb(20, 20, 20);
}
@media (max-width: 800px) {
:root {
--background-image: linear-gradient(0deg, rgba(10, 10, 10, 1), rgb(10, 10, 10, 0)),
url("{{background-image}}") !important;
}
}

View file

@ -1,12 +1,7 @@
:root {
--bg-color: #fff;
--text-color: rgb(10, 10, 10);
--background-image: linear-gradient(
90deg,
rgba(10, 10, 10, 0.4),
rgb(10, 10, 10, 0.4)
),
url("{{{background}}}");
--background-background: #fff;
--gradient: linear-gradient(90deg, #009bef, #f00);
}
:root {
--bg-color: #fff;
--text-color: rgb(10, 10, 10);
--blog-gray-color: rgb(80, 80, 80);
--background-image: linear-gradient(90deg, rgba(10, 10, 10, 0.4), rgb(10, 10, 10, 0.4)), url("{{background}}");
--background-background: #fff;
}

View file

@ -1,75 +0,0 @@
#! /usr/bin/env node
/* Argument parser */
const program = require("commander");
process.env.OUT_DIR = process.env.OUT_DIR || process.cwd();
const { buildCommand } = require("../build");
const { updateCommand } = require("../update");
const { uiCommand } = require("../ui");
const { runCommand } = require("../run");
const { version } = require("../package.json");
function collect(val, memo) {
memo.push(val);
return memo;
}
program
.command("build <username>")
.description(
"Build site with your GitHub username. This will be used to customize your site"
)
.option("-t, --theme [theme]", "specify a theme to use", "light")
.option("-b, --background [background]", "set the background image")
.option("-f, --fork", "includes forks with repos")
.option("-s, --sort [sort]", "set default sort for repository", "created")
.option("-o, --order [order]", "set default order on sort", "asc")
.option("-c, --codepen [username]", "specify codepen username")
.option("-d, --dev [username]", "specify dev username")
.option("-D, --dribbble [username]", "specify dribbble username")
.option("-e, --email [email]", "specify email")
.option("-F, --facebook [username]", "specify facebook username")
.option("-i, --instagram [username]", "specify instagram username")
.option("-k, --keybase [username]", "specify keybase username")
.option("-m, --medium [username]", "specify medium username")
.option("-r, --reddit [username]", "specify reddit username")
.option("-E, --stackexchange [user id]", "specify stackexchange user id")
.option("-S, --steam [username]", "specify steam username")
.option("-T, --telegram [username]", "specify telegram username")
.option("-w, --twitter [username]", "specify twitter username")
.option("-x, --xda [user id]", "specify xda user id")
.option("-y, --youtube [user id]", "specify youtube user id")
.action(buildCommand);
program
.command("update")
.description("Update user and repository data")
.action(updateCommand);
program
.command("ui")
.description("Create and Manage gitfolio with ease")
.action(uiCommand);
program
.command("run")
.description("Run build files")
.option("-p, --port [port]", "provide a port for localhost, default is 3000")
.action(runCommand);
program.on("command:*", () => {
console.log("Unknown Command: " + program.args.join(" "));
program.help();
});
program
.version(version, "-v --version")
.usage("<command> [options]")
.parse(process.argv);
if (program.args.length === 0) {
program.help();
}

71
blog.js Normal file
View file

@ -0,0 +1,71 @@
const program = require('commander');
const fs = require('fs');
const jsdom = require('jsdom').JSDOM,
options = {
resources: "usable"
};
program
.version('0.1.2')
.option('-t, --title [title]', 'give blog a title')
.option('-s, --subtitle [subtitle]', 'give blog a subtitle', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.')
.option('-p, --pagetitle [pagetitle]', 'give blog page a title')
.option('-f, --folder [folder]', 'give folder a title (use "-" instead of spaces)')
.parse(process.argv);
function createBlog(title, subtitle, pagetitle, folder) {
if (!fs.existsSync(`./dist/blog/${folder}`)){
fs.mkdirSync(`./dist/blog/${folder}`, { recursive: true });
}
fs.copyFile('./assets/blog/blogTemplate.html', `./dist/blog/${folder}/index.html`, (err) => {
if (err) throw err;
jsdom.fromFile(`./dist/blog/${folder}/index.html`, options).then(function (dom) {
let window = dom.window, document = window.document;
var style = document.createElement("link");
style.setAttribute("rel","stylesheet")
style.setAttribute("href","../../index.css");
document.getElementsByTagName("head")[0].appendChild(style);
document.getElementsByTagName("title")[0].textContent = pagetitle;
document.getElementById("blog_title").textContent = title;
document.getElementById("blog_sub_title").textContent = subtitle;
fs.writeFile(`./dist/blog/${folder}/index.html`, '<!DOCTYPE html>'+window.document.documentElement.outerHTML, function (error){
if (error) throw error;
var blog_data = {
"url_title": pagetitle,
"title": title,
"sub_title": subtitle,
"top_image": "https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450",
"visible": true }
fs.readFile("./dist/blog.json", function (err , data) {
if (err) throw err;
var old_blogs = JSON.parse(data);
old_blogs.push(blog_data);
fs.writeFile('./dist/blog.json', JSON.stringify(old_blogs, null, ' '), function(err){
if (err) throw err;
console.log('Blog Created Successfully in "blog" folder.');
});
});
});
}).catch(function(error){
console.log(error);
});
});
}
if (program.title) {
/* Check if build has been executed before blog this will prevent it from giving "link : index.css" error */
if (!fs.existsSync(`./dist/index.html`) || !fs.existsSync(`./dist/index.css`)){
return console.log("You need to run build command before using blog one");
}
if (!program.pagetitle) {
program.pagetitle = program.title;
}
if (!program.folder) {
program.folder = program.title;
}
createBlog(program.title, program.subtitle, program.pagetitle, program.folder);
} else {
console.log("Provide a title to create a new blog");
}

205
build.js
View file

@ -1,113 +1,92 @@
// Filepath utilities
const path = require("path");
// Promise library
const bluebird = require("bluebird");
const hbs = require("handlebars");
// Creates promise-returning async functions from callback-passed async functions
const fs = bluebird.promisifyAll(require("fs"));
const fse = require("fs-extra");
const { updateHTML } = require("./populate");
const { getConfig, outDir } = require("./utils");
const assetDir = path.resolve(`${__dirname}/assets/`);
const config = path.join(outDir, "config.json");
const tempfont = path.resolve(assetDir, "fonts");
const fonts = path.join(outDir, "assets/fonts");
/**
* Creates the stylesheet used by the site from a template stylesheet.
*
* Theme styles are added to the new stylesheet depending on command line
* arguments.
*/
async function populateCSS({
theme = "light",
background = "https://source.unsplash.com/1280x720/?wallpaper",
} = {}) {
// Get the theme the user requests. Defaults to 'light'
theme = `${theme}.css`;
const template = path.resolve(assetDir, "index.css");
const stylesheet = path.join(outDir, "index.css");
try {
await fs.accessAsync(outDir, fs.constants.F_OK);
} catch (error) {
await fs.mkdirAsync(outDir);
}
// Copy over the template CSS stylesheet
await fs.copyFileAsync(template, stylesheet);
// Copy Fonts
fse.copySync(tempfont, fonts);
// Get an array of every available theme
const themes = await fs.readdirAsync(path.join(assetDir, "themes"));
if (!themes.includes(theme)) {
console.error('Error: Requested theme not found. Defaulting to "light".');
theme = "light";
}
// Read in the theme stylesheet
let themeSource = await fs.readFileSync(path.join(assetDir, "themes", theme));
themeSource = themeSource.toString("utf-8");
const themeTemplate = hbs.compile(themeSource);
const styles = themeTemplate({
background: `${background}`,
});
// Add the user-specified styles to the new stylesheet
await fs.appendFileAsync(stylesheet, styles);
// Update the config file with the user's theme choice
const data = await getConfig();
data[0].theme = theme;
await fs.writeFileAsync(config, JSON.stringify(data, null, " "));
}
async function populateConfig(opts) {
const data = await getConfig();
Object.assign(data[0], opts);
await fs.writeFileAsync(config, JSON.stringify(data, null, " "));
}
async function buildCommand(username, program) {
await populateCSS(program);
let types;
if (!program.include || !program.include.length) {
types = ["all"];
} else {
types = program.include;
}
const opts = {
sort: program.sort,
order: program.order,
includeFork: Boolean(program.fork),
types,
codepen: program.codepen,
dev: program.dev,
dribbble: program.dribbble,
email: program.email,
facebook: program.facebook,
instagram: program.instagram,
keybase: program.keybase,
medium: program.medium,
reddit: program.reddit,
stackexchange: program.stackexchange,
steam: program.steam,
telegram: program.telegram,
twitter: program.twitter,
xda: program.xda,
youtube: program.youtube,
};
await populateConfig(opts);
updateHTML(("%s", username), opts);
}
module.exports = {
buildCommand,
populateCSS,
populateConfig,
};
/* Argument parser */
const program = require('commander');
/* Filepath utilities */
const path = require('path');
/* Promise library */
const bluebird = require('bluebird');
const hbs = require('handlebars');
/* Creates promise-returning async functions
from callback-passed async functions */
const fs = bluebird.promisifyAll(require('fs'));
const { updateHTML } = require('./populate');
/* Specify the options the program uses */
program
.version('0.1.2')
.option('-n, --name [username]', 'your GitHub username. This will be used to customize your site')
.option('-t, --theme [theme]', 'specify a theme to use')
.option('-b, --background [background]', 'set the background image')
.option('-f, --fork', 'includes forks with repos')
.option('-s, --sort [sort]', 'set default sort for repository')
.option('-o, --order [order]', 'set default order on sort')
.parse(process.argv);
const config = './dist/config.json';
const assetDir = path.resolve('./assets/');
const outDir = path.resolve('./dist/');
/**
* Creates the stylesheet used by the site from a template stylesheet.
*
* Theme styles are added to the new stylesheet depending on command line
* arguments.
*/
async function populateCSS() {
/* Get the theme the user requests. Defaults to 'light' */
let theme = `${program.theme || 'light'}.css`; /* Site theme, defaults to 'light' */
let template = path.resolve(assetDir, 'index.css');
let stylesheet = path.join(outDir, 'index.css');
try {
await fs.accessAsync(outDir, fs.constants.F_OK);
} catch (err) {
await fs.mkdirAsync(outDir);
}
/* Copy over the template CSS stylesheet */
await fs.copyFileAsync(template, stylesheet);
/* Get an array of every available theme */
let themes = await fs.readdirAsync(path.join(assetDir, 'themes'));
if (!themes.includes(theme)) {
console.error('Error: Requested theme not found. Defaulting to "light".');
theme = 'light';
}
/* Read in the theme stylesheet */
let themeSource = await fs.readFileSync(path.join(assetDir, 'themes', theme));
themeSource = themeSource.toString('utf-8');
let themeTemplate = hbs.compile(themeSource);
let styles = themeTemplate({
'background': `${process.background || 'https://images.unsplash.com/photo-1553748024-d1b27fb3f960?w=1450'}`
})
/* Add the user-specified styles to the new stylesheet */
await fs.appendFileAsync(stylesheet, styles);
/* Update the config file with the user's theme choice */
let data = await fs.readFileAsync(config);
data = JSON.parse(data);
data[0].theme = theme;
await fs.writeFileAsync(config, JSON.stringify(data, null, ' '));
}
populateCSS();
if (program.name) {
let sort = program.sort ? program.sort : 'created';
let order = -1;
let includeFork = false;
if(program.order){
if(program.order === 'asc')
order = 1;
else if(program.order === 'desc')
order = -1;
}
if(program.fork){
includeFork = true;
}
updateHTML(('%s', program.name), sort, order, includeFork);
} else {
console.error("Error: Please provide a GitHub username.");
}

View file

@ -1,11 +0,0 @@
[
{
"username": null,
"name": null,
"userimg": null,
"sort": null,
"order": null,
"includeFork": null,
"theme": "light.css"
}
]

1
dist/blog.json vendored Normal file
View file

@ -0,0 +1 @@
[]

8
dist/config.json vendored Normal file
View file

@ -0,0 +1,8 @@
[
{
"username": null,
"name": null,
"userimg": null,
"theme": "light"
}
]

7487
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,59 +1,20 @@
{
"name": "gitfolio",
"version": "0.1.5",
"description": "a portfolio website for everyone to showcase their work",
"main": "build.js",
"bin": "bin/gitfolio.js",
"scripts": {
"build": "OUT_DIR='./dist' node bin/gitfolio.js build dilllxd -f -t dark -s updated -e dylan@dylanh.dev -i dilllx -k dilll -r dilllx -S dilll -w dilllxd -y UCuQ2CKTDMlxugSQsDJKVeQA",
"cli": "OUT_DIR='./dist' node bin/gitfolio.js",
"clean": "rm -rf ./dist/*",
"prettier": "prettier --write \"./**/*.{js,jsx,json,html,css,md}\"",
"snyk-protect": "snyk protect",
"prepare": "npm run snyk-protect",
"test": "snyk test"
},
"author": {
"name": "@imfunniee and community",
"email": "imfunny@wybemf.com",
"url": "https://imfunniee.github.io"
},
"bugs": "https://github.com/imfunniee/gitfolio/issues",
"homepage": "https://github.com/imfunniee/gitfolio",
"keywords": [
"personal-website",
"github",
"portfolio",
"portfolio website",
"gitfolio",
"git"
],
"repository": {
"type": "git",
"url": "https://github.com/imfunniee/gitfolio"
},
"license": "GPL-3.0",
"dependencies": {
"bluebird": "^3.5.4",
"body-parser": "^1.19.0",
"commander": "^2.20.0",
"ejs": "3.0.2",
"express": "^4.17.0",
"fs-extra": "9.0.0",
"github-emoji": "^1.1.1",
"got": "11.0.2",
"handlebars": "4.7.6",
"jsdom": "16.2.2",
"ncp": "^2.0.0",
"snyk": "1.307.0"
},
"devDependencies": {
"eslint": "^6.8.0",
"prettier": "2.0.5",
"stylelint": "13.3.3",
"stylelint-config-prettier": "^8.0.1",
"stylelint-config-standard": "^20.0.0",
"stylelint-prettier": "^1.1.2"
},
"snyk": true
}
{
"name": "gitfolio",
"version": "0.1.2",
"description": "portfolio website for showcasing your work",
"main": "build.js",
"scripts": {
"clean": "rm -f dist/index.*",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "imfunny",
"license": "ISC",
"dependencies": {
"bluebird": "^3.5.4",
"commander": "^2.20.0",
"github-emoji": "^1.1.0",
"got": "^9.6.0",
"handlebars": "^4.1.2",
"jsdom": "^15.0.0"
}
}

View file

@ -1,428 +1,117 @@
const fs = require("fs");
const emoji = require("github-emoji");
const jsdom = require("jsdom").JSDOM,
options = {
resources: "usable"
};
const { getConfig, outDir } = require("./utils");
const { getRepos, getUser } = require("./api");
function convertToEmoji(text) {
if (text == null) return;
text = text.toString();
var pattern = /(?<=:\s*).*?(?=\s*:)/gs;
if (text.match(pattern) != null) {
var str = text.match(pattern);
str = str.filter(function(arr) {
return /\S/.test(arr);
});
for (i = 0; i < str.length; i++) {
if (emoji.URLS[str[i]] != undefined) {
text = text.replace(
`:${str[i]}:`,
`<img src="${emoji.URLS[str[i]]}" class="emoji">`
);
}
}
return text;
} else {
return text;
}
}
module.exports.updateHTML = (username, opts) => {
const {
includeFork,
codepen,
dev,
dribbble,
email,
facebook,
instagram,
keybase,
medium,
reddit,
stackexchange,
steam,
telegram,
twitter,
xda,
youtube
} = opts;
//add data to assets/index.html
jsdom
.fromFile(`${__dirname}/assets/index.html`, options)
.then(function(dom) {
let window = dom.window,
document = window.document;
(async () => {
try {
console.log("Building HTML/CSS...");
const repos = await getRepos(username, opts);
for (var i = 0; i < repos.length; i++) {
let element;
if (repos[i].fork == false) {
element = document.getElementById("work_section");
} else if (includeFork == true) {
document.getElementById("forks").style.display = "block";
element = document.getElementById("forks_section");
} else {
continue;
}
element.innerHTML += `
<a href="${repos[i].html_url}" target="_blank">
<section>
<div class="section_title">${repos[i].name}</div>
<div class="about_section">
<span style="display:${
repos[i].description == undefined
? "none"
: "block"
};">${convertToEmoji(repos[i].description)}</span>
</div>
<div class="bottom_section">
<span style="display:${
repos[i].language == null
? "none"
: "inline-block"
};"><span class="iconify" data-icon="mdi-code-tags"></span>&nbsp; ${
repos[i].language
}</span>
<span><span class="iconify" data-icon="mdi-star"></span>&nbsp; ${
repos[i].stargazers_count
}</span>
<span><span class="iconify" data-icon="mdi-source-fork"></span>&nbsp; ${
repos[i].forks_count
}</span>
</div>
</section>
</a>`;
}
const user = await getUser(username);
document.title = user.login;
var icon = document.createElement("link");
icon.setAttribute("rel", "icon");
icon.setAttribute("href", user.avatar_url);
icon.setAttribute("type", "image/png");
document.getElementsByTagName("head")[0].appendChild(icon);
document.getElementById(
"profile_img"
).style.background = `url('${user.avatar_url}') center center`;
document.getElementsByTagName("head")[0].innerHTML += `
<meta name="description" content="${user.bio}" />
<meta property="og:image" content="${user.avatar_url}" />
<meta property="og:type" content="profile" />
<meta property="og:title" content="${user.login}" />
<meta property="og:url" content="${user.html_url}" />
<meta property="og:description" content="${user.bio}" />
<meta property="profile:username" content="${user.login}" />
<meta name="twitter:image:src" content="${user.avatar_url}" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="${user.login}" />
<meta name="twitter:description" content="${user.bio}" />`;
//Socials
document.getElementById(
"username"
).innerHTML = `<span id="text" style="display:${
user.name == null || !user.name ? "none" : "block"
};"></span><div class='console-underscore' id='console'>&#95;</div>`;
document.getElementById("about").innerHTML = `
<span style="display:${
user.company == null || !user.company ? "none" : "block"
};"><span class="iconify" data-icon="mdi-face"></span> &nbsp; ${
user.company
}</span>
<span style="display:block;"><a href="${
user.html_url
}"><span class="iconify" data-icon="mdi-github-circle"></span>&nbsp;&nbsp;@${
user.login
}</a></span>
<span style="display:${
email == null ? "none !important" : "block"
};"><a href="mailto:${email}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-email"></span>&nbsp;&nbsp;${email}</a></span>
<span style="display:${
user.location == null || !user.location ? "none" : "block"
};"><a href="https://www.google.com/maps/search/?api=1&query=${
user.location
}"><span class="iconify" data-icon="mdi-map-marker"></span>&nbsp;&nbsp;${
user.location
}</a></span>
<span style="display:${
user.hireable == false || !user.hireable ? "none" : "block"
};"><span class="iconify" data-icon="mdi-account-tie"></span> &nbsp;&nbsp; Available for hire</span>
<div class="socials">
<span style="display:${
codepen == null ? "none !important" : "block"
};"><a href="https://codepen.io/${codepen}" target="_blank" class="socials"><span class="iconify" data-icon="simple-icons:codepen"></span></a></span>
<span style="display:${
dev == null ? "none !important" : "block"
};"><a href="https://dev.to/${dev}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-dev-to"></span></a></span>
<span style="display:${
dribbble == null ? "none !important" : "block"
};"><a href="https://www.dribbble.com/${dribbble}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-dribbble"></span></a></span>
<span style="display:${
facebook == null ? "none !important" : "block"
};"><a href="https://facebook.com/${facebook}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-facebook-box"></span></a></span>
<span style="display:${
instagram == null ? "none !important" : "block"
};"><a href="https://www.instagram.com/${instagram}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-instagram"></span></a></span>
<span style="display:${
keybase == null ? "none !important" : "block"
};"><a href="https://keybase.io/${keybase}" target="_blank" class="socials"><span class="iconify" data-icon="simple-icons:keybase"></span></a></span>
<span style="display:${
medium == null ? "none !important" : "block"
};"><a href="https://medium.com/@${medium}" target="_blank" class="socials"><span class="iconify" data-icon="fa-brands:medium-m"></span></a></span>
<span style="display:${
reddit == null ? "none !important" : "block"
};"><a href="https://www.reddit.com/u/${reddit}" target="_blank" class="socials"><span class="iconify" data-icon="fa:reddit-alien"></span></a></span>
<span style="display:${
stackexchange == null ? "none !important" : "block"
};"><a href="https://stackexchange.com/users/${stackexchange}" target="_blank" class="socials"><span class="iconify" data-icon="mdi:stack-exchange"></span></a></span>
<span style="display:${
steam == null ? "none !important" : "block"
};"><a href="https://steamcommunity.com/id/${steam}" target="_blank" class="socials"><span class="iconify" data-icon="mdi:steam"></span></a></span>
<span style="display:${
telegram == null ? "none !important" : "block"
};"><a href="https://t.me/${telegram}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-telegram"></span></a></span>
<span style="display:${
twitter == null ? "none !important" : "block"
};"><a href="https://www.twitter.com/${twitter}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-twitter"></span></a></span>
<span style="display:${
xda == null ? "none !important" : "block"
};"><a href="https://forum.xda-developers.com/member.php?u=${xda}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-xda"></span></a></span>
<span style="display:${
youtube == null ? "none !important" : "block"
};"><a href="https://www.youtube.com/channel/${youtube}" target="_blank" class="socials"><span class="iconify" data-icon="mdi-youtube"></span></a></span>
</div>
`;
//Script
document.getElementById("script").innerHTML = `<script>
const magicProjectsGrid = new MagicGrid({
container: "#work_section",
animate: false,
gutter: 30, // default gutter size
static: true,
useMin: false,
maxColumns: 2,
useTransform: true
});
const magicForksGrid = new MagicGrid({
container: "#forks_section",
animate: false,
gutter: 30, // default gutter size
static: true,
useMin: false,
maxColumns: 2,
useTransform: true
});
$("document").ready(() => {
magicProjectsGrid.listen();
magicForksGrid.listen();
});
// function([string1, string2],target id,[color1,color2])
consoleText(["${user.name}", "${user.bio}"], "text", [
"white",
"white"
]);
function consoleText(words, id, colors) {
if (colors === undefined) colors = ["#fff"];
var visible = true;
var con = document.getElementById("console");
var letterCount = 1;
var x = 1;
var waiting = false;
var target = document.getElementById(id);
target.setAttribute("style", "color:" + colors[0]);
window.setInterval(function() {
if (letterCount === 0 && waiting === false) {
waiting = true;
target.innerHTML = words[0].substring(0, letterCount);
window.setTimeout(function() {
var usedColor = colors.shift();
colors.push(usedColor);
var usedWord = words.shift();
words.push(usedWord);
x = 1;
target.setAttribute("style", "color:" + colors[0]);
letterCount += x;
waiting = false;
}, 1000);
} else if (letterCount === words[0].length + 1 && waiting === false) {
waiting = true;
window.setTimeout(function() {
x = -1;
letterCount += x;
waiting = false;
}, 1000);
} else if (waiting === false) {
target.innerHTML = words[0].substring(0, letterCount);
letterCount += x;
}
}, 120);
window.setInterval(function() {
if (visible === true) {
con.className = "console-underscore hidden";
visible = false;
} else {
con.className = "console-underscore";
visible = true;
}
}, 400);
}
</script>`;
//add data to config.json
const data = await getConfig();
data[0].username = user.login;
data[0].name = user.name;
data[0].userimg = user.avatar_url;
await fs.writeFile(
`${outDir}/config.json`,
JSON.stringify(data, null, " "),
function(err) {
if (err) throw err;
console.log("Config file updated.");
}
);
await fs.writeFile(
`${outDir}/gamer.html`,
`<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="7; url='https://www.youtube.com/playlist?list=UUp0gATorETNZ6ttOTMeV7jA'" />
</head>
<body>
<p>Please follow <a href="https://www.youtube.com/playlist?list=UUp0gATorETNZ6ttOTMeV7jA">this link</a>.</p>
</body>
</html>`,
function(error) {
if (error) throw error;
console.log("Wrote gamer.html");
}
);
await fs.writeFile(
`${outDir}/vps.html`,
`<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="7; url='http://207.244.250.120/'" />
</head>
<body>
<p>Please follow <a href="http://207.244.250.120/">this link</a>.</p>
</body>
</html>`,
function(error) {
if (error) throw error;
console.log("Wrote vps.html");
}
);
await fs.writeFile(
`${outDir}/keybase.txt`,
`==================================================================
https://keybase.io/dilll
--------------------------------------------------------------------
I hereby claim:
* I am an admin of https://dylanh.dev
* I am dilll (https://keybase.io/dilll) on keybase.
* I have a public key with fingerprint 9D2F 65D5 8FE7 5DED 1B8E 3B12 E58D 4317 E154 D022
To do so, I am signing this object:
{
"body": {
"key": {
"eldest_kid": "0120390f95b82550aa978d217eeac984e667e5b39cf01f64dadcd4899090a19919780a",
"fingerprint": "9d2f65d58fe75ded1b8e3b12e58d4317e154d022",
"host": "keybase.io",
"key_id": "e58d4317e154d022",
"kid": "0101b1f37fc0a6e762d2f16c51c2cc86129d89630638017cb71f17f23a082b1820130a",
"uid": "9432f8a7178f663cc1f70c77cbe51319",
"username": "dilll"
},
"service": {
"hostname": "dylanh.dev",
"protocol": "https:"
},
"type": "web_service_binding",
"version": 1
},
"ctime": 1556653778,
"expire_in": 157680000,
"prev": "6311ea796c2fdce63368d0422d2cd6fd5382355c793a82d8c50cac59ed6f147f",
"seqno": 26,
"tag": "signature"
}
which yields the signature:
-----BEGIN PGP MESSAGE-----
Version: Keybase OpenPGP v2.1.0
Comment: https://keybase.io/crypto
yMNxAnicbVJtUFRlFAZpS0AUauJjotQLihEf970f7713Z2oCtGITRpNVK2q5H++F
22676+6ygMCUjSPCxFqSDaPgqINAipKjw4BWG+Q0KCqfDkIwBoOiwAoj1DBE0V0m
/vX+OfOe8zzPec6Zcz3IzyfA90F5SthIRhfm29FakeuT2V7bU4gJFqkA0xZiRrQc
kElCdofBqEiYFsMBgZMcLnO0wBI0jfM8x7ASARiEeJFjKQQhg2iB5EQZBzKkJF4S
JYrlOJzDecBxQIXjPBaHyYo5G9msNsXsUGU5iZAhLdGsjBhaQhIQWEQKgEA0K1Gk
qg5oSsIJQiXmWOxehmpO4O0oQbGoOfVjWLb3P/gV3zgQgEwysojzEDGQUDsCKNJA
JESRhYDgJJaDJA5JFgeMKDBABoxMkDzOEgJgCRyQy75zl+U4iiRklmcAw8oQkqII
ZAYXGZWHaEACzgu0I5uZ/xSpaEkxmUxYcRymppyKiLxb9Y6xUi4w8eacBAk5VZrV
ZnFYRItJzec4HFa71stzFFi9wDwkGP6TMAiKWVJXqDKcyGZXLGZMC1Sk6FC8moCm
IaRJhmHjMJRvVWzIoHgRNANZXH3ePmo7LQZJABDPcFAkZElEkCQhK+EUoa5HlKAs
0SRLkDQtMhzJs4TEijQu8iLNIbUIKEbGvEPtM1swLQFVn3y2qmlXss28I9eGsOK2
1sxnfHwDfJ7VrPLelk+Af/DKxcHxdUtZ60cTy8I+GvAbWVNwMI9yRHy8uOmRoc2K
QpdSTsWk1/1eenx39EL96raLMzvwYHdaTs/8wzPRERvHX+0ypZ7YNFdOkUMD5rPj
o9/de9zx2/PG/ceOFR8Kjvk65OUrT+c2t/j3x1T1pg00zZPV+ANNyJDw1qz+WkYg
MPZf5ks0h3cc8CTWvH+k4AvLlSRqMcov0zV8acyjzD4patr+bnXClsNJoS80Hj0d
OxOyt7b8Ubv4yerPS92N+oCUssLMoSeBMc4+c0lo5OWUquRQrqHZHXFPhy8wkXtE
EGQbvqjv1FygqwbWoG/qg+/3Di7+IGnC83RX689sPbnubtbA3mt/uuZhVHL06+Q/
Ve6asZjm6Bc9+w52x16PG+zVVfU6dRp+MPL4H+vZ3dUHnvvQuHPL3/517+gGO9eW
xt9udr3nE7BQCdomw99ugNuoyl+J/TcnUk/0k41Jr3kmPuvKmtXnRuQU6q6eh3u2
vZQ/fGM67efNp2am6jzdjoyghkuj20/fPxm466nLuatlJL+nqOjQnYo7qypu596t
qfsxrc9Y/W3ThkrPdGJHi7vol4mptUnp02UftCaFT2rcM+c6Y/v0qXrrzvYvsRGb
K8/zV2vD0e/HiKGH3c1zG155I95zpCK+5M3Kc1FNG13O2NopA7t4czI5+6v0YPns
LeW8cuPxraW6n9wwLO/Cv16Pxg0=
=wUqU
-----END PGP MESSAGE-----
And finally, I am proving ownership of this host by posting or
appending to this document.
View my publicly-auditable identity here: https://keybase.io/dilll
==================================================================`,
function(error) {
if (error) throw error;
console.log(`wrote keybase.txt`);
}
);
await fs.writeFile(
`${outDir}/index.html`,
"<!DOCTYPE html>" + window.document.documentElement.outerHTML,
function(error) {
if (error) throw error;
console.log(`Build Complete, Files can be Found @ ${outDir}\n`);
}
);
} catch (error) {
console.log(error);
}
})();
})
.catch(function(error) {
console.log(error);
});
};
const fs = require('fs');
const got = require('got');
const emoji = require('github-emoji');
const jsdom = require('jsdom').JSDOM,
options = {
resources: "usable"
};
function convertToEmoji(text) {
if (text == null) return;
text = text.toString();
if (text.match(/(?<=:\s*).*?(?=\s*:)/gs) != null) {
var str = text.match(/(?<=:\s*).*?(?=\s*:)/gs);
str = str.filter(function (arr) {
return /\S/.test(arr);
});
for (i = 0; i < str.length; i++) {
if (emoji.URLS[str[i]] != undefined) {
var output = emoji.of(str[i]);
var emojiImage = output.url.replace("assets-cdn.github", "github.githubassets");
text = text.replace(`:${str[i]}:`, `<img src="${emojiImage}" class="emoji">`);
}
}
return text;
} else {
return text;
}
}
module.exports.updateHTML = (username, sort, order, includeFork) => {
//add data to assets/index.html
jsdom.fromFile("./assets/index.html", options).then(function (dom) {
let window = dom.window, document = window.document;
(async () => {
try {
console.log("Building HTML/CSS...");
var repos = await got(`https://api.github.com/users/${username}/repos?sort=${sort}&order=${order}&per_page=1200`);
repos = JSON.parse(repos.body);
for (var i = 0; i < repos.length; i++) {
if(repos[i].fork == false){
document.getElementById("work_section").innerHTML += `
<a href="${repos[i].html_url}" target="_blank">
<section>
<div class="section_title">${repos[i].name}</div>
<div class="about_section">
<span style="display:${repos[i].description == undefined ? 'none' : 'block'};">${convertToEmoji(repos[i].description)}</span>
</div>
<div class="bottom_section">
<span style="display:${repos[i].language == null ? 'none' : 'inline-block'};"><i class="fas fa-code"></i>&nbsp; ${repos[i].language}</span>
<span><i class="fas fa-star"></i>&nbsp; ${repos[i].stargazers_count}</span>
<span><i class="fas fa-code-branch"></i>&nbsp; ${repos[i].forks_count}</span>
</div>
</section>
</a>`;
}else{
if(includeFork == true){
document.getElementById("forks").style.display = "block";
document.getElementById("forks_section").innerHTML += `
<a href="${repos[i].html_url}" target="_blank">
<section>
<div class="section_title">${repos[i].name}</div>
<div class="about_section">
<span style="display:${repos[i].description == undefined ? 'none' : 'block'};">${convertToEmoji(repos[i].description)}</span>
</div>
<div class="bottom_section">
<span style="display:${repos[i].language == null ? 'none' : 'inline-block'};"><i class="fas fa-code"></i>&nbsp; ${repos[i].language}</span>
<span><i class="fas fa-star"></i>&nbsp; ${repos[i].stargazers_count}</span>
<span><i class="fas fa-code-branch"></i>&nbsp; ${repos[i].forks_count}</span>
</div>
</section>
</a>`;
}
}
}
var user = await got(`https://api.github.com/users/${username}`);
user = JSON.parse(user.body);
document.title = user.login;
var icon = document.createElement("link");
icon.setAttribute("rel", "icon");
icon.setAttribute("href", user.avatar_url);
icon.setAttribute("type", "image/png");
document.getElementsByTagName("head")[0].appendChild(icon);
document.getElementById("profile_img").style.background = `url('${user.avatar_url}') center center`
document.getElementById("username").innerHTML = `<span style="display:${user.name == null || !user.name ? 'none' : 'block'};">${user.name}</span>@${user.login}`;
//document.getElementById("github_link").href = `https://github.com/${user.login}`;
document.getElementById("userbio").innerHTML = convertToEmoji(user.bio);
document.getElementById("userbio").style.display = user.bio == null || !user.bio ? 'none' : 'block';
document.getElementById("about").innerHTML = `
<span style="display:${user.company == null || !user.company ? 'none' : 'block'};"><i class="fas fa-users"></i> &nbsp; ${user.company}</span>
<span style="display:${user.email == null || !user.email ? 'none' : 'block'};"><i class="fas fa-envelope"></i> &nbsp; ${user.email}</span>
<span style="display:${user.blog == null || !user.blog ? 'none' : 'block'};"><i class="fas fa-link"></i> &nbsp; ${user.blog}</span>
<span style="display:${user.location == null || !user.location ? 'none' : 'block'};"><i class="fas fa-map-marker-alt"></i> &nbsp;&nbsp; ${user.location}</span>
<span style="display:${user.hireable == false || !user.hireable ? 'none' : 'block'};"><i class="fas fa-user-tie"></i> &nbsp;&nbsp; Available for hire</span>`;
//add data to config.json
fs.readFile("./dist/config.json", function (err, data) {
if (err) throw err;
data = JSON.parse(data);
data[0].username = user.login;
data[0].name = user.name;
data[0].userimg = user.avatar_url;
fs.writeFile('./dist/config.json', JSON.stringify(data, null, ' '), function (err) {
if (err) throw err;
});
});
fs.writeFile('dist/index.html', '<!DOCTYPE html>' + window.document.documentElement.outerHTML, function (error) {
if (error) throw error;
console.log("Build Complete");
process.exit(0)
});
} catch (error) {
console.log(error);
}
})();
}).catch(function (error) {
console.log(error);
});
}

22
run.js
View file

@ -1,22 +0,0 @@
const path = require("path");
const express = require("express");
const outDir = path.resolve("./dist/" || process.env.OUT_DIR);
const app = express();
app.use(express.static(`${outDir}`));
function runCommand(program) {
const port = program.port ? program.port : 3000;
app.get("/", (req, res) => {
res.sendFile("/index.html");
});
app.listen(port);
console.log(
`\nGitfolio running on port ${port}, Navigate to http://localhost:${port} in your browser\n`
);
}
module.exports = {
runCommand
};

114
ui.js
View file

@ -1,114 +0,0 @@
const fs = require("fs");
const express = require("express");
const jsdom = require("jsdom").JSDOM;
const { updateHTML } = require("./populate");
const { populateCSS, populateConfig } = require("./build");
const { updateCommand } = require("./update");
const app = express();
app.set("view engine", "ejs");
app.use(express.static(__dirname + "/views"));
app.set("views", __dirname + "/views");
app.use(
express.json({
limit: "50mb"
})
);
app.use(
express.urlencoded({
limit: "50mb",
extended: true
})
);
const port = 3000;
global.DOMParser = new jsdom().window.DOMParser;
const { outDir } = require("./utils");
function uiCommand() {
app.get("/", (req, res) => {
res.render("index.ejs");
});
app.get("/update", (req, res) => {
if (!fs.existsSync(`${outDir}/config.json`)) {
return res.send(
'You need to run build command before using update<br><a href="/">Go Back</a>'
);
}
updateCommand();
res.redirect("/");
});
app.post("/build", (req, res) => {
const { username } = req.body;
if (!username) {
return res.send("username can't be empty");
}
const sort = req.body.sort ? req.body.sort : "created";
const order = req.body.order ? req.body.order : "asc";
const includeFork = req.body.fork === "true";
const types = ["owner"];
const codepen = req.body.codepen ? req.body.codepen : null;
const dev = req.body.dev ? req.body.dev : null;
const dribbble = req.body.dribbble ? req.body.dribbble : null;
const email = req.body.email ? req.body.email : null;
const facebook = req.body.facebook ? req.body.facebook : null;
const instagram = req.body.instagram ? req.body.instagram : null;
const keybase = req.body.keybase ? req.body.keybase : null;
const medium = req.body.medium ? req.body.medium : null;
const reddit = req.body.reddit ? req.body.reddit : null;
const stackexchange = req.body.stackexchange
? req.body.stackexchange
: null;
const steam = req.body.steam ? req.body.steam : null;
const telegram = req.body.telegram ? req.body.telegram : null;
const twitter = req.body.twitter ? req.body.twitter : null;
const xda = req.body.xda ? req.body.xda : null;
const youtube = req.body.youtube ? req.body.youtube : null;
const background = req.body.background
? req.body.background
: "https://source.unsplash.com/1280x720/?wallpaper";
const theme = req.body.theme === "on" ? "dark" : "light";
const opts = {
sort,
order,
includeFork,
types,
codepen,
dev,
dribbble,
email,
facebook,
instagram,
keybase,
medium,
reddit,
stackexchange,
steam,
telegram,
twitter,
xda
};
updateHTML(username, opts);
populateCSS({
background,
theme
});
populateConfig(opts);
res.redirect("/");
});
console.log("\nStarting...");
app.listen(port);
console.log(
`The GUI is running on port ${port}, Navigate to http://localhost:${port} in your browser\n`
);
}
module.exports = {
uiCommand
};

View file

@ -1,40 +1,13 @@
const { getConfig } = require("./utils");
const { updateHTML } = require("./populate");
async function updateCommand() {
const data = await getConfig();
const { username } = data[0];
if (username === null) {
console.log(
"username not found in config.json, please run build command before using update"
);
return;
}
const opts = {
sort: data[0].sort,
order: data[0].order,
includeFork: data[0].includeFork,
types: data[0].types,
codepen: data[0].codepen,
dev: data[0].dev,
dribbble: data[0].dribbble,
email: data[0].email,
facebook: data[0].facebook,
instagram: data[0].instagram,
keybase: data[0].keybase,
medium: data[0].medium,
reddit: data[0].reddit,
stackexchange: data[0].stackexchange,
steam: data[0].steam,
telegram: data[0].telegram,
twitter: data[0].twitter,
xda: data[0].xda,
youtube: data[0].youtube
};
updateHTML(username, opts);
}
module.exports = {
updateCommand
};
const fs = require('fs');
const {updateHTML} = require('./populate');
fs.readFile("./dist/config.json", function (err , data) {
if (err) throw err;
data = JSON.parse(data);
var username = data[0].username;
if(!username || username == null){
console.log("username not found in config.json, please run build command before using update");
return;
}
updateHTML(username);
});

View file

@ -1,33 +0,0 @@
const path = require("path");
const bluebird = require("bluebird");
const fs = bluebird.promisifyAll(require("fs"));
const outDir = path.resolve("./dist/" || process.env.OUT_DIR);
const configPath = path.join(outDir, "config.json");
const defaultConfigPath = path.resolve(`${__dirname}/default/config.json`);
/**
* Tries to read file from out dir,
* if not present returns default file contents
*/
async function getFileWithDefaults(file, defaultFile) {
try {
await fs.accessAsync(file, fs.constants.F_OK);
} catch (error) {
const defaultData = await fs.readFileAsync(defaultFile);
return JSON.parse(defaultData);
}
const data = await fs.readFileAsync(file);
return JSON.parse(data);
}
async function getConfig() {
return getFileWithDefaults(configPath, defaultConfigPath);
}
module.exports = {
outDir,
getConfig
};

Binary file not shown.

View file

@ -1,173 +0,0 @@
@import url("https://fonts.googleapis.com/css?family=Poppins");
@import url("https://fonts.googleapis.com/css?family=Questrial");
@font-face {
font-family: "Circular";
src: url("./font/Circular.otf");
}
body {
margin: 0%;
padding: 0%;
width: 100vw;
max-width: 100vw;
overflow-x: hidden;
align-items: center;
font-family: "Poppins", sans-serif;
background: rgb(250, 250, 250) !important;
will-change: auto;
}
header {
width: 90vw;
padding: 4vh 5vw;
font-weight: bold;
background: rgb(255, 255, 255);
font-size: 32px;
}
header b {
font-family: "Circular", sans-serif;
}
header a {
font-size: 16px;
margin: 1.8vh 0;
margin-left: 4vw;
color: #000;
text-decoration: none;
transition: 0.4s ease-in-out;
}
header a:hover {
color: #bebebe;
}
form {
width: 90vw;
padding: 2vh 5vw;
}
form .button {
margin: 2vh 0;
}
.input {
margin: 1.5vh 0 !important;
}
.label {
display: inline-block !important;
margin-right: 25px;
font-weight: bold;
}
button {
transition: 0.4s ease-in-out !important;
}
button:hover {
color: #fff;
background: #000 !important;
}
.-size-small {
margin-right: 1vw !important;
}
#top_image {
width: 100vw;
height: 50vh;
position: absolute;
top: 14vh;
left: 0;
background: linear-gradient(0deg, rgb(250, 250, 250), rgb(200, 200, 200));
background-size: cover !important;
background-repeat: no-repeat !important;
z-index: 1;
text-align: right;
}
.remove i {
font-size: 14px;
margin-right: 3px;
}
#top_image i {
font-size: 20px;
position: absolute;
z-index: 5;
top: 4vh;
right: 5vw;
padding: 15px 15px;
background: #fff;
color: rgb(0, 0, 0);
border-radius: 50%;
}
#top_image i:hover {
cursor: pointer;
}
.div_for_buttons {
margin-top: 5vh;
}
.para {
font-size: 17px;
line-height: 25px;
word-spacing: 1.2px;
margin: 5vh 0;
background: transparent;
border: 0;
width: 100%;
font-family: "Questrial", sans-serif;
resize: none;
height: auto;
overflow-y: hidden;
}
.para span {
padding: 2px 4px;
background: #000;
color: #fff !important;
}
.remove {
margin-bottom: 2vh 0;
font-weight: bold;
transition: 0.4s ease-in-out;
font-size: 16px;
}
.remove:hover {
cursor: pointer;
color: rgb(255, 70, 70);
}
::selection {
color: #fff;
background: #000;
}
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: #fff;
}
::-webkit-scrollbar-thumb {
background: #000;
}
input,
textarea:focus {
outline: none;
}
::placeholder {
color: #000;
}

View file

@ -1,247 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Gitfolio UI</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css"
/>
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"
integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr"
crossorigin="anonymous"
/>
<link rel="stylesheet" type="text/css" href="./css/index.css" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/zeva-ui/zeva/dist/css/zeva.min.css"
/>
</head>
<body class="body-light">
<header>
<b>gitfolio</b>
<a href="/update" style="float: right">Update</a>
<a href="/" style="float: right">Home</a>
</header>
<form method="post" action="build">
<h3>Build or Edit Portfolio</h3>
<input
type="text"
class="input h-weight-bold"
placeholder="username"
id="username"
name="username"
required
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="background"
name="background"
id="background"
/>
<h3>Sort By :</h3>
<label class="label">
Star
<input type="radio" name="sort" value="star" />
<span class="radio"></span>
</label>
<label class="label">
Created
<input type="radio" name="sort" value="created" checked />
<span class="radio"></span>
</label>
<label class="label">
Updated
<input type="radio" name="sort" value="updated" />
<span class="radio"></span>
</label>
<label class="label">
Pushed
<input type="radio" name="sort" value="pushed" />
<span class="radio"></span>
</label>
<label class="label">
Full Name
<input type="radio" name="sort" value="full_name" />
<span class="radio"></span>
</label>
<h3>Order By :</h3>
<label class="label">
Asc
<input type="radio" name="order" value="asc" checked />
<span class="radio"></span>
</label>
<label class="label">
Desc
<input type="radio" name="order" value="desc" />
<span class="radio"></span>
</label>
<br />
<br />
<label class="label">
Use Dark Theme
<input type="checkbox" id="theme" name="theme" />
<span class="checkbox"></span>
</label>
<label class="label">
Include Forks
<input type="checkbox" id="fork" name="fork" value="true" />
<span class="checkbox"></span>
</label>
<label class="label">
Include Socials
<input type="checkbox" id="socials" name="socials" />
<span class="checkbox"></span>
</label>
<div style="display: none" id="input_for_socials">
<input
type="text"
class="input h-weight-bold"
placeholder="codepen username"
id="codepen"
name="codepen"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="dev username"
id="dev"
name="dev"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="dribbble username"
id="dribbble"
name="dribbble"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="email address"
id="email"
name="email"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="facebook username"
id="facebook"
name="facebook"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="instagram username"
id="instagram"
name="instagram"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="keybase username"
id="keybase"
name="keybase"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="medium username"
id="medium"
name="medium"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="reddit username"
id="reddit"
name="reddit"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="stackexchange username"
id="stackexchange"
name="stackexchange"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="steam username"
id="steam"
name="steam"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="telegram username"
id="telegram"
name="telegram"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="twitter username"
id="twitter"
name="twitter"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="xda user id"
id="xda"
name="xda"
/>
<br />
<input
type="text"
class="input h-weight-bold"
placeholder="youtube user id"
id="youtube"
name="youtube"
/>
</div>
<br />
<br />
<button type="submit" class="button" id="build">Build</button>
</form>
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/gh/zeva-ui/zeva/dist/js/index.min.js"
></script>
<script type="text/javascript">
document.querySelector("#socials").addEventListener("change", event => {
if (event.target.checked) {
document.querySelector("#input_for_socials").style.display = "block";
} else {
document.querySelector("#input_for_socials").style.display = "none";
}
});
</script>
</body>
</html>