Full Code of bradtraversy/codegig for AI

master 8e8f43cfb3f3 cached
14 files
13.5 KB
4.3k tokens
1 symbols
1 requests
Download .txt
Repository: bradtraversy/codegig
Branch: master
Commit: 8e8f43cfb3f3
Files: 14
Total size: 13.5 KB

Directory structure:
gitextract_0ajwmxgi/

├── .gitignore
├── README.md
├── app.js
├── config/
│   └── database.js
├── models/
│   └── Gig.js
├── package.json
├── public/
│   └── css/
│       └── style.css
├── routes/
│   └── gigs.js
└── views/
    ├── add.handlebars
    ├── error.handlebars
    ├── gigs.handlebars
    ├── index.handlebars
    └── layouts/
        ├── landing.handlebars
        └── main.handlebars

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules
.env

================================================
FILE: README.md
================================================
# CodeGig

> Simple Job find app for coders. This app uses Node, Express, Sequalize (Postgres) and Handlebars.

## Quick Start

``` bash
# Install dependencies
npm install

# Serve on localhost:5000
npm start
# Dev Server (Nodemon)
npm run dev
```

## App Info

### Author

Brad Traversy
[Traversy Media](http://www.traversymedia.com)

### Version

1.0.0

### License

This project is licensed under the MIT License


================================================
FILE: app.js
================================================
const express = require('express');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const path = require('path');

// Database
const db = require('./config/database');

// Test DB
db.authenticate()
  .then(() => console.log('Database connected...'))
  .catch(err => console.log('Error: ' + err))

const app = express();

// Handlebars
app.engine('handlebars', exphbs({ defaultLayout: 'main' }));
app.set('view engine', 'handlebars');

// Body Parser
app.use(express.urlencoded({ extended: false }));

// Set static folder
app.use(express.static(path.join(__dirname, 'public')));

// Index route
app.get('/', (req, res) => res.render('index', { layout: 'landing' }));

// Gig routes
app.use('/gigs', require('./routes/gigs'));

const PORT = process.env.PORT || 5000;

app.listen(PORT, console.log(`Server started on port ${PORT}`));

================================================
FILE: config/database.js
================================================
const Sequelize = require('sequelize');
const dotenv = require('dotenv');

dotenv.config();

module.exports =  new Sequelize(process.env.DATABASE_URL, {
  host: 'localhost',
  dialect: 'postgres',
  operatorsAliases: false,

  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  },
});

================================================
FILE: models/Gig.js
================================================
const Sequelize = require('sequelize');
const db = require('../config/database');

const Gig = db.define('gig', {
  title: {
    type: Sequelize.STRING
  },
  technologies: {
    type: Sequelize.STRING
  },
  description: {
    type: Sequelize.STRING
  },
  budget: {
    type: Sequelize.STRING
  },
  contact_email: {
    type: Sequelize.STRING
  }
});

Gig.sync().then(() => {
  console.log('table created');
});
module.exports = Gig;

================================================
FILE: package.json
================================================
{
  "name": "codegig",
  "version": "1.0.0",
  "description": "Simple job find app for coders",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js"
  },
  "author": "Brad Traversy",
  "license": "MIT",
  "dependencies": {
    "dotenv": "^8.1.0",
    "express": "^4.16.4",
    "express-handlebars": "^3.0.0",
    "pg": "^7.7.1",
    "pg-hstore": "^2.3.2",
    "sequelize": "^4.44.3"
  },
  "devDependencies": {
    "nodemon": "^1.18.8"
  }
}


================================================
FILE: public/css/style.css
================================================
@import url('https://fonts.googleapis.com/css?family=Lato');

:root {
  --primary-color: #568c9b;
  --primary-hover-color: #64a5b7;
  --bg-color: #333;
  --box-shadow: 3px 4px 12px rgba(0, 0, 0, 0.7);
}

* {
  box-sizing: border-box;
}

body {
  font-family: 'Lato', sans-serif;
  margin: 0;
  color: #333;
  background: #f4f4f4;
}

ul {
  list-style: none;
  padding: 0;
}

a {
  color: #fff;
  text-decoration: none;
}

a:hover {
  color: var(--primary-color);
}

.container {
  max-width: 960px;
  padding: 1rem 4rem;
  margin: auto;
  overflow: hidden;
}

.error {
  padding: 5px;
  border: #777 dotted 1px;
  margin-bottom: 15px;
}

/* Header */
header {
  display: flex;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 6rem;
}

header nav ul {
  display: flex;
}

header nav li {
  margin: 0 1rem;
}

/* Login Button Spacing */
/*header nav li:last-child {
  margin-left: -5px;
}*/

header.inner {
  background: var(--bg-color);
  border-bottom: 4px solid var(--primary-color);
  position: relative;
  box-shadow: var(--box-shadow);
}

/* Buttons */
.btn {
  color: #fff;
  padding: 0.6rem;
  border: 1px solid #ccc;
  transition: all 0.7s;
}

.btn:hover {
  background: var(--primary-color);
  border: 1px solid var(--primary-color);
  color: #fff;
}

.btn-reverse {
  background: var(--primary-color);
  border: 1px solid var(--primary-color);
}

.btn-reverse:hover {
  background: var(--primary-hover-color);
  border: 1px solid var(--primary-hover-color);
}

/* Home Search */
.search-wrap {
  background: url('../img/showcase.jpg') no-repeat center center fixed;
  background-size: cover;
  height: 100vh;
  width: 100%;
  padding: 1.3rem 3rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.search-wrap h1 {
  font-size: 3rem;
  font-weight: 800;
  color: #fff;
  margin: 0 0 1.5rem;
  text-align: center;
}

.search-form input[type='submit'] {
  background: var(--primary-color);
  border: 1px solid var(--primary-color);
  color: #fff;
  padding: 0 2rem;
  cursor: pointer;
  transition: all 0.8s;
}

.search-form input[type='submit']:hover {
  background: var(--primary-hover-color);
  border: 1px solid var(--primary-hover-color);
}

.search-form {
  display: flex;
  width: 600px;
  box-shadow: var(--box-shadow);
}

.search-form i {
  color: #333;
}

/* Everything in the search form */
.search-form > * {
  border: 0;
  padding: 0 0 0 10px;
  background: #fff;
  line-height: 50px;
  font-size: 1rem;
  border-radius: 0;
  outline: 0;
}

input[type='search'] {
  flex-basis: 600px;
}

/* Gigs */
.gig {
  background: var(--bg-color);
  border-bottom: 4px solid var(--primary-color);
  color: #fff;
  padding: 1rem;
  margin-bottom: 1rem;
  box-shadow: var(--box-shadow);
}

.gig ul {
  list-style: none;
  display: flex;
}

.gig li {
  margin-right: 0.5rem;
  padding: 0.6rem;
}

.gig .tech span {
  color: var(--primary-color);
}

/* Form */
.form-wrap {
  margin: auto;
  background: var(--bg-color);
  color: #fff;
  padding: 1rem 3rem 3rem;
  margin-top: 3rem;
  border-bottom: 4px solid var(--primary-color);
  box-shadow: var(--box-shadow);
}

.form-wrap.reg-form,
.form-wrap.login-form {
  width: 60%;
}

.form-wrap h1,
.form-wrap h2,
.form-wrap p {
  text-align: center;
}

.form-wrap .btn {
  margin-top: 1rem;
  display: block;
  width: 100%;
  text-align: center;
  font-size: 18px;
}

label {
  display: block;
  margin-bottom: 0.5rem;
}

.input-box {
  padding: 0.5rem;
  font-size: 18px;
  width: 100%;
  margin-bottom: 1.2rem;
}

/* Tablets */
@media (max-width: 800px) {
  .container {
    padding: 1rem 2rem;
  }

  header {
    flex-direction: column;
    padding: 0.3rem !important;
  }

  .search-form {
    width: 100%;
  }

  input[type='search'] {
    flex-basis: 100%;
  }

  .search-wrap h1 {
    font-size: 2rem;
  }

  .search-wrap {
    padding: 2.3rem;
  }

  .gig ul {
    flex-direction: column;
  }

  .gig .btn {
    display: block;
    margin-top: 1rem;
    text-align: center;
  }

  .form-wrap.reg-form,
  .form-wrap.login-form {
    width: 80%;
  }
}

/* Smartphones */
@media (max-width: 500px) {
  .container {
    padding: 1rem;
  }

  header nav li {
    margin: 0 10px;
  }

  .search-form {
    display: flex;
    flex-direction: column;
  }

  input[type='search'] {
    flex-basis: 0;
  }

  .search-form i {
    display: none;
  }

  .form-wrap {
    padding: 1rem 2rem 2rem;
  }

  .form-wrap.reg-form,
  .form-wrap.login-form {
    width: 100%;
  }
}


================================================
FILE: routes/gigs.js
================================================
const express = require('express');
const router = express.Router();
const db = require('../config/database');
const Gig = require('../models/Gig');
const Sequelize = require('sequelize');
const Op = Sequelize.Op;

// Get gig list
router.get('/', (req, res) => 
  Gig.findAll()
    .then(gigs => res.render('gigs', {
        gigs
      }))
    .catch(err => res.render('error', {error: err})));

// Display add gig form
router.get('/add', (req, res) => res.render('add'));

// Add a gig
router.post('/add', (req, res) => {
  let { title, technologies, budget, description, contact_email } = req.body;
  let errors = [];

  // Validate Fields
  if(!title) {
    errors.push({ text: 'Please add a title' });
  }
  if(!technologies) {
    errors.push({ text: 'Please add some technologies' });
  }
  if(!description) {
    errors.push({ text: 'Please add a description' });
  }
  if(!contact_email) {
    errors.push({ text: 'Please add a contact email' });
  }

  // Check for errors
  if(errors.length > 0) {
    res.render('add', {
      errors,
      title, 
      technologies, 
      budget, 
      description, 
      contact_email
    });
  } else {
    if(!budget) {
      budget = 'Unknown';
    } else {
      budget = `$${budget}`;
    }

    // Make lowercase and remove space after comma
    technologies = technologies.toLowerCase().replace(/,[ ]+/g, ',');

    // Insert into table
    Gig.create({
      title,
      technologies,
      description,
      budget,
      contact_email
    })
      .then(gig => res.redirect('/gigs'))
      .catch(err => res.render('error', {error:err.message}))
  }
});

// Search for gigs
router.get('/search', (req, res) => {
  let { term } = req.query;

  // Make lowercase
  term = term.toLowerCase();

  Gig.findAll({ where: { technologies: { [Op.like]: '%' + term + '%' } } })
    .then(gigs => res.render('gigs', { gigs }))
    .catch(err => res.render('error', {error: err}));
});

module.exports = router;

================================================
FILE: views/add.handlebars
================================================
<section id="add" class="container">
    <div class="form-wrap">
      <h1>Add A Gig</h1>
      <p>Your contact email will be shared with registered users to apply to your gig</p>
      {{#each errors}}
        <div class="error">
          <p>{{text}}</p>
        </div>
      {{/each}}
      <form action="/gigs/add" method="POST">
        <div class="input-group">
          <label for="title">Gig Title</label>
          <input type="text" name="title" id="title" class="input-box" placeholder="eg. Small Wordpress website, React developer"
            maxlength="100" value={{title}}>
        </div>
        <div class="input-group">
          <label for="technologies">Technologies Needed</label>
          <input type="text" name="technologies" id="technologies" class="input-box" placeholder="eg. javascript, react, PHP"
          maxlength="100" value={{technologies}}>
        </div>
        <div class="input-group">
          <label for="budget">Budget (Leave blank for unknown)</label>
          <input type="number" name="budget" id="budget" class="input-box" placeholder="eg. 500, 5000, 10000" value={{budget}}>
        </div>
        <div class="input-group">
          <label for="description">Gig Description</label>
          <textarea name="description" id="description" class="input-box" placeholder="Describe the details of the gig"
            rows="10">{{description}}</textarea>
        </div>
        <div class="input-group">
          <label for="budget">Contact Email</label>
          <input type="email" name="contact_email" id="contactemail" class="input-box" placeholder="Enter an email" value={{contact_email}}>
        </div>
        <input type="submit" value="Add Gig" class="btn btn-reverse">
      </form>
    </div>
  </section>

================================================
FILE: views/error.handlebars
================================================
<section id="gigs" class="container">
  <h1> An error occured </h1>
  <br><br>
  <h2>{{error}}</h2>
</section>

================================================
FILE: views/gigs.handlebars
================================================
<section id="gigs" class="container">
    <h1>All Gigs</h1>

    {{#each gigs}}
      <div class="gig">
      <h3>{{title}}</h3>
      <p>{{description}}</p>
      <ul>
        <li>Budget: {{budget}}</li>
        <li><a href="mailto:{{contact_email}}" class="btn btn-reverse">Apply Now</a></li>
      </ul>
      <div class="tech">
        <small>Technologies Needed: <span>{{technologies}}</span></small>
      </div>
    </div>
    {{else}}
      <p>No gigs available</p>
    {{/each}}
    
  </section>

================================================
FILE: views/index.handlebars
================================================
<section id="search" class="search-wrap">
    <h1>Find A Coding Gig</h1>
    <form action="/gigs/search" class="search-form">
      <i class="fas fa-search"></i>
      <input type="search" name="term" placeholder="Javascript, PHP, Rails, etc...">
      <input type="submit" value="Search">
    </form>
  </section>

================================================
FILE: views/layouts/landing.handlebars
================================================
<!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">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU"
    crossorigin="anonymous">

  <link rel="stylesheet" href="/css/style.css">
  <title>CodeGig</title>
</head>

<body>
  <header>
    <h2><a href="/"><i class="fas fa-code"></i>
        CodeGig</a></h2>
    <nav>
      <ul>
        <li>
          <a href="/">Home</a>
        </li>
        <li>
          <a href="/gigs">All Gigs</a>
        </li>
        <li>
          <a href="/gigs/add">Add Gig</a>
        </li>
      </ul>
    </nav>
  </header>

  {{{body}}}
</body>

</html>

================================================
FILE: views/layouts/main.handlebars
================================================
 <!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">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU"
    crossorigin="anonymous">


  <link rel="stylesheet" href="/css/style.css">
  <title>CodeGig</title>
</head>

<body>
  <header class="inner">
    <h2><a href="/"><i class="fas fa-code"></i>
        CodeGig</a></h2>
    <nav>
      <ul>
        <li>
          <a href="/">Home</a>
        </li>
        <li>
          <a href="/gigs">All Gigs</a>
        </li>
        <li>
          <a href="/gigs/add">Add Gig</a>
        </li>   
      </ul>
    </nav>
  </header>

  <div class="container">
    {{{body}}}
  </div>
</body>

</html>
Download .txt
gitextract_0ajwmxgi/

├── .gitignore
├── README.md
├── app.js
├── config/
│   └── database.js
├── models/
│   └── Gig.js
├── package.json
├── public/
│   └── css/
│       └── style.css
├── routes/
│   └── gigs.js
└── views/
    ├── add.handlebars
    ├── error.handlebars
    ├── gigs.handlebars
    ├── index.handlebars
    └── layouts/
        ├── landing.handlebars
        └── main.handlebars
Download .txt
SYMBOL INDEX (1 symbols across 1 files)

FILE: app.js
  constant PORT (line 32) | const PORT = process.env.PORT || 5000;
Condensed preview — 14 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (16K chars).
[
  {
    "path": ".gitignore",
    "chars": 17,
    "preview": "node_modules\n.env"
  },
  {
    "path": "README.md",
    "chars": 446,
    "preview": "# CodeGig\r\n\r\n> Simple Job find app for coders. This app uses Node, Express, Sequalize (Postgres) and Handlebars.\r\n\r\n## Q"
  },
  {
    "path": "app.js",
    "chars": 872,
    "preview": "const express = require('express');\nconst exphbs = require('express-handlebars');\nconst bodyParser = require('body-parse"
  },
  {
    "path": "config/database.js",
    "chars": 303,
    "preview": "const Sequelize = require('sequelize');\nconst dotenv = require('dotenv');\n\ndotenv.config();\n\nmodule.exports =  new Seque"
  },
  {
    "path": "models/Gig.js",
    "chars": 436,
    "preview": "const Sequelize = require('sequelize');\nconst db = require('../config/database');\n\nconst Gig = db.define('gig', {\n  titl"
  },
  {
    "path": "package.json",
    "chars": 480,
    "preview": "{\n  \"name\": \"codegig\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Simple job find app for coders\",\n  \"main\": \"app.js\",\n  \"s"
  },
  {
    "path": "public/css/style.css",
    "chars": 4855,
    "preview": "@import url('https://fonts.googleapis.com/css?family=Lato');\r\n\r\n:root {\r\n  --primary-color: #568c9b;\r\n  --primary-hover-"
  },
  {
    "path": "routes/gigs.js",
    "chars": 1961,
    "preview": "const express = require('express');\nconst router = express.Router();\nconst db = require('../config/database');\nconst Gig"
  },
  {
    "path": "views/add.handlebars",
    "chars": 1768,
    "preview": "<section id=\"add\" class=\"container\">\n    <div class=\"form-wrap\">\n      <h1>Add A Gig</h1>\n      <p>Your contact email wi"
  },
  {
    "path": "views/error.handlebars",
    "chars": 110,
    "preview": "<section id=\"gigs\" class=\"container\">\n  <h1> An error occured </h1>\n  <br><br>\n  <h2>{{error}}</h2>\n</section>"
  },
  {
    "path": "views/gigs.handlebars",
    "chars": 505,
    "preview": "<section id=\"gigs\" class=\"container\">\n    <h1>All Gigs</h1>\n\n    {{#each gigs}}\n      <div class=\"gig\">\n      <h3>{{titl"
  },
  {
    "path": "views/index.handlebars",
    "chars": 314,
    "preview": "<section id=\"search\" class=\"search-wrap\">\n    <h1>Find A Coding Gig</h1>\n    <form action=\"/gigs/search\" class=\"search-f"
  },
  {
    "path": "views/layouts/landing.handlebars",
    "chars": 849,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, i"
  },
  {
    "path": "views/layouts/main.handlebars",
    "chars": 905,
    "preview": " <!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, "
  }
]

About this extraction

This page contains the full source code of the bradtraversy/codegig GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 14 files (13.5 KB), approximately 4.3k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!