├── Procfile ├── .gitignore ├── public ├── images │ ├── favicon.png │ ├── noimage.jpg │ ├── screen.jpg │ ├── fileshare.jpg │ ├── dropdown.svg │ ├── file.svg │ ├── filesad.svg │ ├── filehappy.svg │ └── fileintro.svg └── styles │ ├── main.css │ └── main.css.map ├── assets ├── scripts │ ├── actions │ │ ├── types.js │ │ └── index.js │ ├── reducers │ │ ├── auth_reducer.js │ │ ├── profile_reducer.js │ │ ├── index.js │ │ └── file_reducer.js │ ├── helpers │ │ └── index.js │ ├── index.js │ └── components │ │ ├── app.js │ │ ├── display_bar.js │ │ ├── file.js │ │ ├── file_display.js │ │ └── file_search.js └── styles │ ├── utilities │ ├── _brand.scss │ ├── _typography.scss │ ├── _tools.scss │ ├── _form.scss │ └── _normalize.scss │ ├── partials │ └── _fileForm.scss │ └── main.scss ├── .stylelintrc ├── config ├── routes.js └── passport.js ├── server.js ├── views ├── app.jade └── index.jade ├── readme.md ├── package.json └── gulpfile.js /Procfile: -------------------------------------------------------------------------------- 1 | web: node server.js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | -------------------------------------------------------------------------------- /public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewminns/slack/HEAD/public/images/favicon.png -------------------------------------------------------------------------------- /public/images/noimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewminns/slack/HEAD/public/images/noimage.jpg -------------------------------------------------------------------------------- /public/images/screen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewminns/slack/HEAD/public/images/screen.jpg -------------------------------------------------------------------------------- /public/images/fileshare.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewminns/slack/HEAD/public/images/fileshare.jpg -------------------------------------------------------------------------------- /assets/scripts/actions/types.js: -------------------------------------------------------------------------------- 1 | export const FETCH_AUTH = 'FETCH_AUTH'; 2 | export const FETCH_PROFILE = 'FETCH_PROFILE'; 3 | export const FETCH_FILES = 'FETCH_FILES'; 4 | export const DESTROY_FILE = 'DESTROY_FILE'; -------------------------------------------------------------------------------- /assets/styles/utilities/_brand.scss: -------------------------------------------------------------------------------- 1 | $body : ( 2 | font-family: "poppins", sans-serif, 3 | font-weight: 300 4 | ); 5 | 6 | $headings: ( 7 | font-family: "poppins", sans-serif, 8 | font-weight: 600 9 | ); 10 | 11 | $green: #62F1AC; 12 | 13 | // Sass 14 | -------------------------------------------------------------------------------- /assets/scripts/reducers/auth_reducer.js: -------------------------------------------------------------------------------- 1 | import { FETCH_AUTH } from '../actions/types'; 2 | 3 | export default function(state = [], action) { 4 | switch(action.type) { 5 | case FETCH_AUTH: 6 | return { ...state, profile: action.payload.data } 7 | default: 8 | return state; 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /assets/scripts/reducers/profile_reducer.js: -------------------------------------------------------------------------------- 1 | import { FETCH_PROFILE } from '../actions/types'; 2 | 3 | export default function(state = [], action) { 4 | switch(action.type) { 5 | case FETCH_PROFILE: 6 | return { ...state, data: action.payload.data } 7 | default: 8 | return state; 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /assets/scripts/helpers/index.js: -------------------------------------------------------------------------------- 1 | export default function formatBytes(bytes,decimals) { 2 | if(bytes == 0) return '0 Bytes'; 3 | var k = 1000; 4 | var dm = decimals + 1 || 3; 5 | var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; 6 | var i = Math.floor(Math.log(bytes) / Math.log(k)); 7 | return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; 8 | } -------------------------------------------------------------------------------- /assets/scripts/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import authReducer from './auth_reducer'; 3 | import profileReducer from './profile_reducer'; 4 | import fileReducer from './file_reducer'; 5 | 6 | const rootReducer = combineReducers({ 7 | auth: authReducer, 8 | profileInfo: profileReducer, 9 | files: fileReducer 10 | }); 11 | 12 | export default rootReducer; -------------------------------------------------------------------------------- /assets/scripts/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import { createStore, applyMiddleware } from 'redux'; 5 | import reducers from './reducers'; 6 | import promise from 'redux-promise'; 7 | 8 | import App from './components/app'; 9 | 10 | const createStoreWithMiddleware = applyMiddleware(promise)(createStore); 11 | 12 | ReactDOM.render( 13 | 14 | 15 | 16 | , document.querySelector('main#app')); 17 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "string-quotes" : "double", 4 | "number-leading-zero" : "never", 5 | "value-list-comma-space-before" : "never", 6 | "declaration-colon-space-after" : "always", 7 | "block-no-empty" : true, 8 | "block-opening-brace-space-before" : "always", 9 | "selector-combinator-space-after" : "always", 10 | "selector-combinator-space-before" : "always", 11 | "selector-pseudo-element-colon-notation" : "double", 12 | "declaration-block-no-duplicate-properties" : true, 13 | "declaration-block-trailing-semicolon" : "always" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /public/images/dropdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Triangle 1 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /assets/scripts/reducers/file_reducer.js: -------------------------------------------------------------------------------- 1 | import { FETCH_FILES, DESTROY_FILE } from '../actions/types'; 2 | 3 | export default function(state = [], action) { 4 | switch(action.type) { 5 | case FETCH_FILES: 6 | return { ...state, fileList: action.payload.data.files } 7 | case DESTROY_FILE: 8 | if (action.payload.data.ok) { 9 | let files = {...state} 10 | let fileID = action.payload.config.url.split("&file=").pop(); 11 | let fileArray = files.fileList.filter(val => val.id !== fileID ); 12 | return { ...state, fileList: fileArray } 13 | } else { 14 | return {...state} 15 | } 16 | default: 17 | return state; 18 | } 19 | } -------------------------------------------------------------------------------- /public/images/file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Shape 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /assets/styles/utilities/_typography.scss: -------------------------------------------------------------------------------- 1 | $base-px: 1.5rem !default; 2 | 3 | html { font-size: 62.5%; } 4 | 5 | // 1.333 Perfect Fourth 6 | body { 7 | font-size: $base-px; 8 | line-height: 1.428; 9 | @include print-styles($body); 10 | } 11 | 12 | h1 { font-size: 3.157em; } 13 | h2 { font-size: 1.9em; } 14 | h3 { font-size: 1.3em; } 15 | h4 { font-size: 1.333em; } 16 | 17 | h1, h2, h3, h4, h5, h6 { font-family: inherit; } 18 | 19 | h1, h2, h3, h4, h5, h6 { 20 | color: inherit; 21 | line-height: 1.2; 22 | letter-spacing: -.04em; 23 | @include print-styles($headings) 24 | } 25 | 26 | h1, h2, h3 { 27 | margin-top: 10px; 28 | margin-bottom: 10px; 29 | } 30 | 31 | p { 32 | font-size: 1em; 33 | line-height: 1.428; 34 | } 35 | 36 | ol, ul, dl { 37 | margin-top: 0; 38 | margin-bottom: 10px; 39 | &:last-child { 40 | margin-bottom: 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /config/routes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = (app, passport) => { 4 | 5 | app.get('/', (req, res) => res.render('index')); 6 | 7 | app.get('/logout', function(req, res){ 8 | console.log('logging out'); 9 | req.logout(); 10 | res.redirect('/'); 11 | }); 12 | 13 | app.get('/auth/slack', passport.authenticate('slack')); 14 | app.get('/auth/slack/callback', passport.authenticate('slack', { 15 | failureRedirect: '/' 16 | }), (req, res) => { 17 | res.redirect('/hooray') 18 | }); 19 | 20 | app.get('/hooray', ensureAuthenticated, (req, res) => { 21 | res.render('app', {profileName: req.user.profile.displayName}) 22 | }); 23 | 24 | app.get('/auth', ensureAuthenticated, (req, res) => { 25 | res.json(req.user); 26 | }) 27 | 28 | } 29 | 30 | function ensureAuthenticated(req, res, next) { 31 | if (req.isAuthenticated()) { 32 | return next(); 33 | } 34 | res.redirect('/') 35 | } -------------------------------------------------------------------------------- /config/passport.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let express = require('express'), 4 | app = express(), 5 | SlackStrategy = require('passport-slack').Strategy; 6 | 7 | if (app.get('env') === 'development') { 8 | require('dotenv').config(); 9 | } 10 | 11 | module.exports = (passport) => { 12 | passport.serializeUser(function(user, done) { 13 | done(null, user); 14 | }); 15 | 16 | passport.deserializeUser(function(user, done) { 17 | done(null, user); 18 | }); 19 | 20 | passport.use(new SlackStrategy({ 21 | clientID: process.env.clientID || process.env.clientID_DEV, 22 | clientSecret: process.env.clientSecret || process.env.clientSecret_DEV, 23 | callbackURL: process.env.CALLBACK || process.env.CALLBACK_DEV, 24 | scope: 'users:read files:read files:write:user' 25 | }, 26 | (accessToken, refreshToken, profile, done) => { 27 | return done(null, {profile : profile, token: accessToken}); 28 | } 29 | )); 30 | 31 | } -------------------------------------------------------------------------------- /assets/styles/utilities/_tools.scss: -------------------------------------------------------------------------------- 1 | @mixin print-styles($map) { 2 | @each $property, $value in $map { 3 | #{$property}: $value; 4 | } 5 | } 6 | 7 | @mixin bp($point) { 8 | @if $point == xl { // 1050px 9 | @media (max-width: 65.625rem) { @content; } 10 | } 11 | @else if $point == lg { // 900px 12 | @media (max-width: 56.25rem) { @content; } 13 | } 14 | @else if $point == md { // 768px 15 | @media (max-width: 48rem) { @content; } 16 | } 17 | @else if $point == sm { // 600px 18 | @media (max-width: 37.5rem) { @content; } 19 | } 20 | @else if $point == xs { // 400px 21 | @media (max-width: 25rem) { @content; } 22 | } 23 | } 24 | 25 | @mixin cf { 26 | *zoom: 1; 27 | &::before, 28 | &::after { 29 | display: table; 30 | content: ""; 31 | line-height: 0; 32 | } 33 | &::after { 34 | clear: both; 35 | } 36 | } 37 | 38 | // Hide text 39 | // --------- 40 | @mixin hide-text { 41 | font: 0/0 a; 42 | color: transparent; 43 | text-shadow: none; 44 | } -------------------------------------------------------------------------------- /assets/scripts/components/app.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import * as actions from '../actions'; 4 | 5 | import DisplayBar from './display_bar'; 6 | import FileSearch from './file_search'; 7 | import FileDisplay from './file_display'; 8 | 9 | class App extends Component { 10 | 11 | componentWillMount() { 12 | 13 | this.props.fetchAuth().then(() => { 14 | let token = this.props.authData.token; 15 | let id = this.props.authData.profile.id; 16 | this.props.fetchProfile(token, id); 17 | }); 18 | } 19 | 20 | render() { 21 | return ( 22 |
23 | 24 |
25 | 26 | 27 |
28 |
29 | ) 30 | } 31 | 32 | } 33 | 34 | function mapStateToProps(state) { 35 | return { 36 | authData: state.auth.profile, 37 | profile: state.profileInfo.data 38 | } 39 | } 40 | 41 | export default connect(mapStateToProps, actions)(App); 42 | -------------------------------------------------------------------------------- /assets/scripts/components/display_bar.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | class DisplayBar extends Component{ 5 | 6 | render() { 7 | let userName = 'loading', 8 | photo = null, 9 | profileData = this.props.profile; 10 | if (typeof profileData !== 'undefined') { 11 | userName = profileData.user.profile.real_name_normalized 12 | photo = profileData.user.profile.image_72; 13 | } 14 | return ( 15 |
16 |
17 |

slack deletron

18 |
19 |
20 |

Oh hey {userName}!

21 | 22 | Logout 23 |
24 |
25 | ) 26 | } 27 | } 28 | 29 | function mapStateToProps(state) { 30 | return { 31 | profile: state.profileInfo.data, 32 | fileGroup: state.files 33 | } 34 | } 35 | 36 | export default connect(mapStateToProps)(DisplayBar); 37 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let express = require('express'), 4 | app = express(), 5 | port = process.env.PORT || 3000, 6 | morgan = require('morgan'), 7 | passport = require('passport'), 8 | bodyParser = require('body-parser'), 9 | session = require('express-session'), 10 | SlackStrategy = require('passport-slack').Strategy; 11 | 12 | if (app.get('env') === 'development') { 13 | require('dotenv').config(); 14 | } 15 | require('./config/passport')(passport); 16 | 17 | app.set('view engine', 'jade'); 18 | 19 | app.use(morgan('dev')); 20 | app.use(bodyParser.urlencoded({ extended: true })); 21 | app.use(bodyParser.json()); 22 | app.use(express.static(__dirname + '/public')); 23 | 24 | app.listen(port, () => console.log(`listening on Port ${port}`)); 25 | 26 | app.use(session({ 27 | secret: process.env.SECRET || process.env.SECRET_DEV, 28 | resave: false, 29 | saveUninitialized: false 30 | })); 31 | app.use(passport.initialize()); 32 | app.use(passport.session()); 33 | 34 | require('./config/routes')(app, passport); 35 | 36 | -------------------------------------------------------------------------------- /assets/scripts/actions/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import { FETCH_AUTH, FETCH_PROFILE, FETCH_FILES, DESTROY_FILE } from './types'; 4 | 5 | export function fetchAuth() { 6 | const request = axios.get('/auth') 7 | return { 8 | type: FETCH_AUTH, 9 | payload: request 10 | } 11 | } 12 | 13 | export function fetchProfile(token, user) { 14 | const request = axios.get(`https://slack.com/api/users.info?token=${token}&user=${user}`); 15 | return { 16 | type: FETCH_PROFILE, 17 | payload: request 18 | } 19 | } 20 | 21 | export function fetchFiles(token, types, userID) { 22 | let data = { 23 | token: token, 24 | types: types 25 | } 26 | if (userID !== 'all') 27 | data.user = userID 28 | const request = axios.get(`https://slack.com/api/files.list`, { params: data }); 29 | return { 30 | type: FETCH_FILES, 31 | payload: request 32 | } 33 | } 34 | 35 | export function destroyFile(token, file) { 36 | const request = axios.get(`https://slack.com/api/files.delete?token=${token}&file=${file}`); 37 | return { 38 | type: DESTROY_FILE, 39 | payload: request 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /views/app.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | head 4 | meta(charset='UTF-8') 5 | title slack deletron - sup #{profileName}! 6 | link(rel='icon', href='images/favicon.png', type='image/png') 7 | link(href='https://fonts.googleapis.com/css?family=Poppins:300,400,700', rel='stylesheet', type='text/css') 8 | link(rel='stylesheet', href='styles/main.css') 9 | body 10 | main#app 11 | script(src='scripts/app.min.js') 12 | script. 13 | !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs'); 14 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 15 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 16 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 17 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 18 | 19 | ga('create', 'UA-76483887-1', 'auto'); 20 | ga('send', 'pageview'); 21 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Slack Deletron 2 | 3 | This tool allows you to delete your extra Slack files from your team account. 4 | 5 | It's built with Express and Passport on the server side, and React and Redux on the client side. 6 | 7 | ## Contributing 8 | 9 | To contribute, fork the repo and then complete the following steps to get up and running. 10 | 11 | 1. Sign up for the Slack Web API at [https://api.slack.com/web](https://api.slack.com/web) and get yourself a Client ID and a Client Secret. In the 'Redirect URI(s)' field, put `http://localhost:3000/auth/slack/callback` 12 | 13 | 14 | 2. Create a `.env` file in the root of the project and add the following details 15 | 16 | ``` 17 | clientID_DEV=CLIENTIDFROMTHESLACKAPI 18 | clientSecret_DEV=CLIENTSECRETFROMTHESLACKAPI 19 | SECRET_DEV=supersupersecretpartytime 20 | CALLBACK_DEV=http://localhost:3000/auth/slack/callback 21 | ``` 22 | 3. Install dependencies 23 | 24 | ``` 25 | npm install 26 | ``` 27 | 28 | 4. In two separate terminals, run the following commands respectively 29 | 30 | ``` 31 | nodemon server.js 32 | gulp 33 | ``` 34 | or...in one terminal window, run 35 | 36 | ``` 37 | npm start 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /assets/styles/partials/_fileForm.scss: -------------------------------------------------------------------------------- 1 | aside.fileControl { 2 | position: fixed; 3 | width: 350px; 4 | height: 100%; 5 | background: #651FFF; 6 | top: 100px; 7 | padding: 20px 25px 150px 25px; 8 | color: white; 9 | overflow: auto; 10 | } 11 | 12 | p.formTitle { 13 | font-size: 2.5rem; 14 | font-weight: 700; 15 | } 16 | 17 | p.fileSize { 18 | font-size: 1.7rem; 19 | font-weight: 700; 20 | } 21 | 22 | .fileTypeList { 23 | margin-bottom: 20px; 24 | } 25 | 26 | header.displayInfo { 27 | margin-bottom: 20px; 28 | padding: 0 20px 20px; 29 | border-bottom: 3px solid #111; 30 | } 31 | 32 | .check-row { 33 | margin: 10px 0; 34 | label { 35 | display: inline-block; 36 | font-size: 1.3rem; 37 | margin-right: 10px; 38 | font-weight: 300; 39 | background: rgba(0,0,0,.7); 40 | padding: 5px 7px 2px; 41 | } 42 | input[type=checkbox] { 43 | appearance: none; 44 | position: relative; 45 | &::before { 46 | content: ""; 47 | border: 3px solid #111; 48 | background: #fafafa; 49 | position: absolute; 50 | top: -17px; 51 | left: 0; 52 | width: 25px; 53 | height: 25px; 54 | } 55 | &:checked::after { 56 | content: "×"; 57 | font-size: 3rem; 58 | position: absolute; 59 | color: #111; 60 | top: -26px; 61 | left: 2px; 62 | } 63 | &:focus { 64 | outline: 0; 65 | } 66 | } 67 | } 68 | 69 | .field { 70 | width: 100%; 71 | margin: 20px 0; 72 | label { 73 | font-size: 1.2rem; 74 | margin-bottom: 5px; 75 | display: inline-block; 76 | padding: 5px 7px 2px; 77 | font-weight: 300; 78 | background: rgba(0,0,0,.7); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /assets/scripts/components/file.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import * as actions from '../actions'; 4 | import formatBytes from '../helpers/index'; 5 | import moment from 'moment'; 6 | 7 | class File extends Component { 8 | 9 | constructor(props) { 10 | super(props) 11 | } 12 | 13 | destroyFile() { 14 | this.props.destroyFile(this.props.authData.token, this.props.details.id); 15 | } 16 | 17 | render() { 18 | let previewImage; 19 | if (this.props.details.mimetype.includes('image')) { 20 | previewImage =
; 21 | } else { 22 | previewImage = null 23 | } 24 | let previewCode; 25 | if(this.props.details.preview) { 26 | previewCode =
{this.props.details.preview}
27 | } else { 28 | previewCode = null 29 | } 30 | return ( 31 |
32 |
33 | {previewImage} 34 | {previewCode} 35 |

{this.props.details.name ? this.props.details.name : 'No filename'}

36 |

{this.props.details.filetype} / {formatBytes(this.props.details.size)}

37 |

{moment.unix(this.props.details.created).fromNow()}

38 |
39 | 40 |
41 | ) 42 | } 43 | 44 | } 45 | 46 | function mapStateToProps(state) { 47 | return { 48 | authData: state.auth.profile, 49 | profile: state.profileInfo.data 50 | } 51 | } 52 | 53 | export default connect(mapStateToProps, actions)(File); 54 | 55 | -------------------------------------------------------------------------------- /assets/styles/utilities/_form.scss: -------------------------------------------------------------------------------- 1 | input, 2 | select, 3 | textarea, 4 | fieldset { 5 | box-sizing: border-box; 6 | margin-top: 0; 7 | margin-bottom: 0; 8 | font-size: 1.5rem; 9 | font-family: inherit; 10 | // -webkit-appearance: none; 11 | } 12 | 13 | .input { 14 | width: 100%; 15 | appearance: none; 16 | font-size: 1.4rem; 17 | padding: 2px 10px; 18 | color: #111; 19 | border: 3px solid #111; 20 | background: #fafafa; 21 | box-shadow: 0 0 10px rgba(0,0,0,.3); 22 | } 23 | 24 | .dropdown { 25 | width: 100%; 26 | appearance: none; 27 | font-size: 1.4rem; 28 | padding: 5px 10px; 29 | color: #111; 30 | background: #fafafa url("../images/dropdown.svg") no-repeat 95% center; 31 | border: 3px solid #111; 32 | border-radius: 0; 33 | box-shadow: 0 0 10px rgba(0,0,0,.3); 34 | } 35 | 36 | label { 37 | vertical-align: middle; 38 | } 39 | 40 | button.login, .login { 41 | display: inline-block; 42 | font-size: 2rem; 43 | background: #111; 44 | border: 0; 45 | padding: 10px 30px; 46 | color: white; 47 | text-decoration: none; 48 | } 49 | 50 | button.deleteAll { 51 | font-size: 2rem; 52 | background: #111; 53 | border: 0; 54 | padding: 10px 30px; 55 | color: white; 56 | transition: all .3s; 57 | box-shadow: 0 0 10px rgba(0,0,0,.3); 58 | &:hover { 59 | background: #E91E63; 60 | } 61 | } 62 | 63 | button.search { 64 | font-size: 2rem; 65 | background: #111; 66 | width: 100%; 67 | color: white; 68 | font-weight: 300; 69 | border: 0; 70 | padding: 10px 30px; 71 | box-shadow: 0 0 10px rgba(0,0,0,.3); 72 | transition: all .8s; 73 | &:focus { 74 | outline: 0; 75 | } 76 | &:hover { 77 | background: #333; 78 | } 79 | } 80 | 81 | button.deleteFile { 82 | border: 0; 83 | background: #111; 84 | display: inline-block; 85 | padding: 10px 30px; 86 | color: white; 87 | transition: all .3s; 88 | &:focus { 89 | outline: 0; 90 | } 91 | &:hover { 92 | background: #E91E63; 93 | } 94 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slackdeletron", 3 | "version": "1.0.0", 4 | "description": "A tool to delete user uploaded files from Slack", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon server.js | gulp" 9 | }, 10 | "author": "Drew Minns", 11 | "license": "ISC", 12 | "dependencies": { 13 | "body-parser": "^1.15.0", 14 | "chai": "^3.5.0", 15 | "chai-jquery": "^2.0.0", 16 | "express": "^4.13.4", 17 | "express-session": "^1.13.0", 18 | "jade": "^1.11.0", 19 | "jsdom": "^8.3.1", 20 | "mocha": "^2.4.5", 21 | "morgan": "^1.7.0", 22 | "passport": "^0.3.2", 23 | "passport-slack": "0.0.4" 24 | }, 25 | "devDependencies": { 26 | "autoprefixer": "^6.3.6", 27 | "axios": "^0.9.1", 28 | "babel-preset-es2015": "^6.6.0", 29 | "babel-preset-react": "^6.5.0", 30 | "babel-preset-stage-1": "^6.5.0", 31 | "babelify": "^7.2.0", 32 | "browser-sync": "^2.11.2", 33 | "browserify": "^13.0.0", 34 | "css-mqpacker": "^4.0.1", 35 | "cssnano": "^3.5.2", 36 | "dotenv": "^2.0.0", 37 | "gulp": "^3.9.1", 38 | "gulp-load-plugins": "^1.2.0", 39 | "gulp-notify": "^2.2.0", 40 | "gulp-plumber": "^1.1.0", 41 | "gulp-postcss": "^6.1.0", 42 | "gulp-sass": "^2.2.0", 43 | "gulp-sourcemaps": "^1.6.0", 44 | "gulp-stylelint": "^1.1.0", 45 | "gulp-uglify": "^1.5.3", 46 | "lost": "^6.7.2", 47 | "moment": "^2.12.0", 48 | "pixrem": "^3.0.0", 49 | "postcss-discard-duplicates": "^2.0.1", 50 | "postcss-reporter": "^1.3.3", 51 | "postcss-scss": "^0.1.7", 52 | "postcss-unique-selectors": "^2.0.2", 53 | "react": "^15.0.1", 54 | "react-dom": "^15.0.1", 55 | "react-masonry-component": "^4.0.0", 56 | "react-redux": "^4.4.4", 57 | "redux": "^3.4.0", 58 | "redux-promise": "^0.5.3", 59 | "stylelint": "^5.4.0", 60 | "vinyl-buffer": "^1.0.0", 61 | "vinyl-source-stream": "^1.1.0" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var gulp = require('gulp'), 3 | browserify = require('browserify'), 4 | source = require('vinyl-source-stream'), 5 | buffer = require('vinyl-buffer'), 6 | babelify = require('babelify'), 7 | browserSync = require('browser-sync'), 8 | reload = browserSync.reload, 9 | scss = require("postcss-scss"), 10 | $ = require('gulp-load-plugins')(); 11 | 12 | const lint = [ 13 | require('stylelint')(), 14 | require('postcss-reporter')({ clearMessages: true, throwError: true }) 15 | ]; 16 | 17 | const postcss = [ 18 | require('css-mqpacker')(), 19 | require('postcss-discard-duplicates')(), 20 | require('postcss-unique-selectors')(), 21 | require('pixrem')(), 22 | require('lost')(), 23 | require('autoprefixer')({ browsers: ['last 5 versions', '> 10%', 'IE 9']}), 24 | require('cssnano')(), 25 | require('postcss-reporter')({ clearMessages: true}) 26 | ]; 27 | 28 | gulp.task('styles', () => { 29 | return gulp.src('./assets/styles/**/*.scss') 30 | .pipe($.plumber({ 31 | errorHandler: $.notify.onError({ 32 | title: "Style Error", 33 | message: "<%= error.message %>" 34 | }) 35 | })) 36 | .pipe($.sourcemaps.init()) 37 | .pipe($.postcss(lint, { syntax: scss })) 38 | .pipe($.sass().on('error', $.sass.logError)) 39 | .pipe($.postcss(postcss)) 40 | .pipe($.sourcemaps.write('.')) 41 | .pipe(gulp.dest('./public/styles')) 42 | .pipe(reload({stream:true})); 43 | }); 44 | 45 | gulp.task('scripts', () => { 46 | browserify('./assets/scripts/index.js') 47 | .transform( babelify, { presets: ['es2015', 'react', 'stage-1'] }) 48 | .bundle().on('error', $.notify.onError({ 49 | title: "JSX Error", 50 | message: "<%= error.message %>" 51 | })) 52 | .pipe(source('app.min.js')) 53 | .pipe(buffer()) 54 | .pipe($.sourcemaps.init({loadMaps: true})) 55 | .pipe($.uglify()) 56 | .pipe($.sourcemaps.write('.')) 57 | .pipe(gulp.dest('./public/scripts')) 58 | .pipe(reload({stream:true})); 59 | }); 60 | 61 | gulp.task('bs', () => { 62 | browserSync({ 63 | proxy: "http://localhost:3000" 64 | }) 65 | }); 66 | 67 | gulp.task('default', ['styles', 'scripts', 'bs'], () => { 68 | gulp.watch('./assets/scripts/**/*.js',['scripts']); 69 | gulp.watch('./assets/styles/**/*.scss', ['styles']); 70 | }); 71 | -------------------------------------------------------------------------------- /public/images/filesad.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | filesad 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /assets/scripts/components/file_display.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import * as actions from '../actions'; 4 | import Masonry from 'react-masonry-component'; 5 | import File from './file'; 6 | 7 | var masonryOptions = { 8 | transitionDuration: '0.2s' 9 | }; 10 | 11 | class FileDisplay extends Component { 12 | 13 | constructor(props) { 14 | super(props) 15 | } 16 | 17 | destroyAll() { 18 | this.props.fileGroup.fileList.map(val => { 19 | this.props.destroyFile(this.props.authData.token, val.id) 20 | }); 21 | // this.props.destroyFile(this.props.authData.token, this.props.details.id); 22 | } 23 | 24 | displayFiles() { 25 | return ( 26 |
27 |
28 |

Remove all files?

29 | 30 |
31 | 36 | {this.props.fileGroup.fileList.map((obj, i) => { 37 | return ( 38 |
39 | 40 |
41 | ) 42 | })} 43 |
44 |
45 | ) 46 | } 47 | 48 | render() { 49 | let dataDisplay; 50 | if (typeof this.props.fileGroup.fileList !== 'undefined' && this.props.fileGroup.fileList.length > 0) { 51 | dataDisplay = this.displayFiles(); 52 | } else if (typeof this.props.fileGroup.fileList !== 'undefined' && this.props.fileGroup.fileList.length === 0) { 53 | dataDisplay = ( 54 |
55 |
56 | 57 |

High Five!

58 |

Looks like there's no files!

59 |

Slack has nothing for you! Try a new search with a different file type to see if there's anything else!

60 |
61 |
62 | ) 63 | } else { 64 | dataDisplay = ( 65 |
66 |
67 | 68 |

Welcome to the Slack Deletron!

69 |

Let's get started!

70 |
    71 |
  1. Use the form to select which file types to search for
  2. 72 |
  3. Click the 'Get Files' button to search
  4. 73 |
  5. Start deleting some files!
  6. 74 |
75 |
76 |
77 | ) 78 | } 79 | return ( 80 |
81 | {dataDisplay} 82 |
83 | ) 84 | } 85 | 86 | } 87 | 88 | function mapStateToProps(state) { 89 | return { 90 | authData: state.auth.profile, 91 | fileGroup: state.files 92 | } 93 | } 94 | 95 | export default connect(mapStateToProps, actions)(FileDisplay); -------------------------------------------------------------------------------- /public/images/filehappy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | filehappy 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /assets/styles/utilities/_normalize.scss: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: sans-serif; 3 | -ms-text-size-adjust: 100%; 4 | -webkit-text-size-adjust: 100%; 5 | } 6 | 7 | body { 8 | margin: 0; 9 | } 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | main, 20 | menu, 21 | nav, 22 | section, 23 | summary { 24 | display: block; 25 | } 26 | 27 | audio, 28 | canvas, 29 | progress, 30 | video { 31 | display: inline-block; /* 1 */ 32 | vertical-align: baseline; /* 2 */ 33 | } 34 | 35 | audio:not([controls]) { 36 | display: none; 37 | height: 0; 38 | } 39 | 40 | [hidden], 41 | template { 42 | display: none; 43 | } 44 | 45 | a { 46 | background-color: transparent; 47 | } 48 | 49 | a:active, 50 | a:hover { 51 | outline: 0; 52 | } 53 | 54 | abbr[title] { 55 | border-bottom: 1px dotted; 56 | } 57 | 58 | b, 59 | strong { 60 | font-weight: bold; 61 | } 62 | 63 | dfn { 64 | font-style: italic; 65 | } 66 | 67 | h1 { 68 | font-size: 2em; 69 | margin: .67em 0; 70 | } 71 | 72 | mark { 73 | background: #ff0; 74 | color: #000; 75 | } 76 | 77 | small { 78 | font-size: 80%; 79 | } 80 | 81 | sub, 82 | sup { 83 | font-size: 75%; 84 | line-height: 0; 85 | position: relative; 86 | vertical-align: baseline; 87 | } 88 | 89 | sup { 90 | top: -.5em; 91 | } 92 | 93 | sub { 94 | bottom: -.25em; 95 | } 96 | 97 | img { 98 | border: 0; 99 | } 100 | 101 | svg:not(:root) { 102 | overflow: hidden; 103 | } 104 | 105 | figure { 106 | margin: 1em 40px; 107 | } 108 | 109 | hr { 110 | -moz-box-sizing: content-box; 111 | box-sizing: content-box; 112 | height: 0; 113 | } 114 | 115 | pre { 116 | overflow: auto; 117 | } 118 | 119 | code, 120 | kbd, 121 | pre, 122 | samp { 123 | font-family: monospace, monospace; 124 | font-size: 1em; 125 | } 126 | 127 | button, 128 | input, 129 | optgroup, 130 | select, 131 | textarea { 132 | color: inherit; /* 1 */ 133 | font: inherit; /* 2 */ 134 | margin: 0; /* 3 */ 135 | } 136 | 137 | button { 138 | overflow: visible; 139 | } 140 | 141 | button, 142 | select { 143 | text-transform: none; 144 | } 145 | 146 | button, 147 | html input[type="button"], /* 1 */ 148 | input[type="reset"], 149 | input[type="submit"] { 150 | -webkit-appearance: button; /* 2 */ 151 | cursor: pointer; /* 3 */ 152 | } 153 | 154 | button[disabled], 155 | html input[disabled] { 156 | cursor: default; 157 | } 158 | 159 | button::-moz-focus-inner, 160 | input::-moz-focus-inner { 161 | border: 0; 162 | padding: 0; 163 | } 164 | 165 | input { 166 | line-height: normal; 167 | } 168 | 169 | input[type="checkbox"], 170 | input[type="radio"] { 171 | box-sizing: border-box; /* 1 */ 172 | padding: 0; /* 2 */ 173 | } 174 | input[type="number"]::-webkit-inner-spin-button, 175 | input[type="number"]::-webkit-outer-spin-button { 176 | height: auto; 177 | } 178 | 179 | input[type="search"] { 180 | -webkit-appearance: textfield; /* 1 */ 181 | -moz-box-sizing: content-box; 182 | -webkit-box-sizing: content-box; /* 2 */ 183 | box-sizing: content-box; 184 | } 185 | 186 | input[type="search"]::-webkit-search-cancel-button, 187 | input[type="search"]::-webkit-search-decoration { 188 | -webkit-appearance: none; 189 | } 190 | 191 | fieldset { 192 | border: 1px solid #c0c0c0; 193 | margin: 0 2px; 194 | padding: .35em .625em .75em; 195 | } 196 | 197 | legend { 198 | border: 0; /* 1 */ 199 | padding: 0; /* 2 */ 200 | } 201 | 202 | textarea { 203 | overflow: auto; 204 | } 205 | 206 | optgroup { 207 | font-weight: bold; 208 | } 209 | 210 | table { 211 | border-collapse: collapse; 212 | border-spacing: 0; 213 | } 214 | 215 | td, 216 | th { 217 | padding: 0; 218 | } 219 | 220 | .clearfix, 221 | %clearfix { 222 | &::after { 223 | content: ""; 224 | display: table; 225 | clear: both; 226 | } 227 | } 228 | 229 | html { 230 | box-sizing: border-box; 231 | } 232 | 233 | *, *::before, *::after { 234 | box-sizing: inherit; 235 | } -------------------------------------------------------------------------------- /public/images/fileintro.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | fileintro 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /views/index.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang='en') 3 | head 4 | meta(charset='UTF-8') 5 | title slack deletron 6 | meta(name="keywords" content="Slack, Deletron, Slack Deletron, Delete Slack Files") 7 | meta(name="description" content="A tool to help delete those cat gifs and other weird files from your Slack team") 8 | meta(name="author" content="Drew Minns") 9 | meta(property="og:title" content="Slack Deletron") 10 | meta(property="og:type" content="website") 11 | meta(property="og:url" content="http://www.slackdeletron.com") 12 | meta(property="og:image" content="http://www.slackdeletron.com/images/fileshare.jpg") 13 | meta(property="og:site_name" content="Slack Deletron") 14 | meta(property="og:description" content="A tool to help delete those cat gifs and other weird files from your Slack team") 15 | meta(name="twitter:card" content="summary" ) 16 | meta(name="twitter:site" content="@drewisthe" ) 17 | meta(name="twitter:title" content="Slack Deletron" ) 18 | meta(name="twitter:description" content="A tool to help delete those cat gifs and other weird files from your Slack team" ) 19 | meta(name="twitter:image" content="http://www.slackdeletron.com/images/fileshare.jpg" ) 20 | link(rel='icon', href='images/favicon.png', type='image/png') 21 | link(href='https://fonts.googleapis.com/css?family=Poppins:300,400,700', rel='stylesheet', type='text/css') 22 | link(rel='stylesheet', href='styles/main.css') 23 | body 24 | header.home-intro 25 | .wrapper 26 | h1 slack deletron 27 | p.lead delete those cat gifs and other weird files 28 | a.login(href="auth/slack") 29 | | login with slack 30 | section.content 31 | .wrapper 32 | .leftcontent 33 | h2 Slack rules and is great for teams. 34 | p 35 | a(href="http://i.giphy.com/m4dxDLChOTGFy.gif") Funny animal gifs 36 | | are really great, however they can quickly bog down the storage on your Slack account. 37 | p 38 | | Slack Deletron allows you to search and delete the files that you have put on your Slack team account. 39 | p 40 | | If you are an admin on your team, you can delete not only your files, but all public files on your team! 41 | .rightcontent 42 | img(src="images/screen.jpg") 43 | section.faq 44 | .wrapper 45 | h2 Hi, you probably have questions 46 | .questionContainer 47 | p.question 48 | | Did Slack build this? 49 | p.answer 50 | | Nope, 51 | a(href="http://drewminns.com") I did. 52 | | and I hope they love it cause they build great products! 53 | .questionContainer 54 | p.question 55 | | It says that I don't have permission to add this to my Slack? 56 | p.answer 57 | | Admins can choose whether team members can add third-party integrations to a Slack Team. If they've turned off permissions, you'll have to ask them to turn them back on for you! 58 | .questionContainer 59 | p.question 60 | | Something isn't working! I wanna help make it better 61 | p.answer 62 | | Help me out! You can submit issues 63 | a(href="https://github.com/drewminns/slack/issues") here 64 | | to help me work out the kinks. If you want to help make the product better, roll up your sleeves, 65 | a(href="https://github.com/drewminns/slack") fork the code 66 | | and go to town! 67 | 68 | footer.home 69 | .wrapper 70 | p 71 | a(href='http://twitter.com/drewisthe') drew minns 72 | | built this 73 | p 74 | a.twitter-share-button(href='https://twitter.com/share', data-url='http://www.slackdeletron.com', data-text='Delete unwanted files from your Slack Team', data-via='drewisthe') Tweet 75 | script. 76 | !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs'); 77 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 78 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 79 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 80 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 81 | 82 | ga('create', 'UA-76483887-1', 'auto'); 83 | ga('send', 'pageview'); 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /assets/styles/main.scss: -------------------------------------------------------------------------------- 1 | @import "utilities/normalize"; 2 | @import "utilities/brand"; 3 | @import "utilities/tools"; 4 | @import "utilities/typography"; 5 | @import "utilities/form"; 6 | 7 | @lost flexbox flex; 8 | 9 | body { 10 | min-height: 100vh; 11 | background: #fafafa; 12 | } 13 | 14 | img { 15 | max-width: 100%; 16 | } 17 | 18 | .wrapper { 19 | margin: 0 auto; 20 | max-width: 980px; 21 | } 22 | 23 | header.home-intro { 24 | text-align: center; 25 | padding: 200px; 26 | background: #651FFF; 27 | border-bottom: 30px solid #111; 28 | box-shadow: 0 2px 25px rgba(0,0,0,.3); 29 | h1 { 30 | font-size: 7rem; 31 | color: #fafafa; 32 | margin: 0; 33 | display: inline-block; 34 | line-height: 1; 35 | padding: 8px 20px 3px; 36 | border: 7px solid #111; 37 | box-shadow: 0 0 10px rgba(0,0,0, .1); 38 | } 39 | p.lead { 40 | color: white; 41 | font-size: 1.8rem; 42 | } 43 | } 44 | 45 | section.content { 46 | padding: 150px 0; 47 | .wrapper { 48 | display: flex; 49 | } 50 | .rightcontent img { 51 | box-shadow: 0 0 10px rgba(0,0,0, .1); 52 | } 53 | .leftcontent { 54 | margin-right: 50px; 55 | p { 56 | line-height: 1.7; 57 | a { 58 | text-decoration: none; 59 | color: #651FFF; 60 | } 61 | } 62 | } 63 | } 64 | 65 | section.faq { 66 | background: #EEEEEE; 67 | padding: 150px 0; 68 | .questionContainer { 69 | margin-bottom: 25px; 70 | p.question { 71 | font-weight: 700; 72 | font-size: 1.9rem; 73 | display: inline-block; 74 | margin-bottom: .6rem; 75 | } 76 | p.answer { 77 | margin-top: 0; 78 | line-height: 2; 79 | font-size: 1.6rem; 80 | a { 81 | font-weight: 700; 82 | color: #651FFF; 83 | text-decoration: none; 84 | } 85 | } 86 | } 87 | } 88 | 89 | footer.home { 90 | background: #111; 91 | padding: 50px 0; 92 | text-align: center; 93 | color: #fafafa; 94 | a { 95 | text-decoration: none; 96 | color: #651FFF; 97 | } 98 | } 99 | 100 | /*=========================================== 101 | = Structural Partials = 102 | ===========================================*/ 103 | 104 | header.app-header { 105 | width: 100%; 106 | top: 0; 107 | left: 0; 108 | padding: 15px 25px; 109 | position: fixed; 110 | z-index: 2; 111 | background: white; 112 | display: flex; 113 | align-items: center; 114 | justify-content: space-between; 115 | box-shadow: 0 2px 25px rgba(0,0,0,.3); 116 | .intro { 117 | position: relative; 118 | h1 { 119 | margin: 0; 120 | display: inline-block; 121 | line-height: 1; 122 | padding: 8px 20px 3px; 123 | border: 4px solid black; 124 | margin-right: 10px; 125 | } 126 | } 127 | } 128 | 129 | .userProfile { 130 | display: flex; 131 | align-items: center; 132 | p { 133 | font-size: 1.8rem; 134 | } 135 | img.profileImage { 136 | display: block; 137 | margin-left: 15px; 138 | } 139 | .logout { 140 | display: inline-block; 141 | margin-left: 15px; 142 | font-size: 1.4rem; 143 | text-decoration: none; 144 | padding: 10px 30px; 145 | color: white; 146 | background: #111; 147 | } 148 | } 149 | 150 | section.fileDisplay { 151 | top: 102px; 152 | height: calc(90vh - 402px); 153 | position: relative; 154 | } 155 | 156 | @import "partials/fileForm"; 157 | 158 | section.fileList { 159 | margin-left: 350px; 160 | width: calc(100% - 350px); 161 | padding: 25px; 162 | position: relative; 163 | } 164 | 165 | .noFiles { 166 | position: absolute; 167 | width: 450px; 168 | top: 50px; 169 | left: calc(50% - 225px); 170 | height: calc(100vh - 350px); 171 | display: flex; 172 | justify-content: center; 173 | align-items: center; 174 | text-align: center; 175 | .noFiles-display { 176 | ol { 177 | text-align: left; 178 | li { 179 | margin-bottom: 1rem; 180 | } 181 | } 182 | } 183 | } 184 | 185 | article.fileCard { 186 | width: 31%; 187 | margin: 0 1% 20px 1%; 188 | background: white; 189 | box-shadow: 0 0 10px rgba(0,0,0, .1); 190 | text-align: center; 191 | padding: 20px; 192 | .previewImg { 193 | height: 179px; 194 | background: #E0E0E0; 195 | overflow: hidden; 196 | margin-bottom: 10px; 197 | display: flex; 198 | flex-flow: row wrap; 199 | align-items: center; 200 | justify-content: center; 201 | } 202 | h3 { 203 | word-break: break-all; 204 | font-weight: 700; 205 | a { 206 | color: #111; 207 | text-decoration: none; 208 | } 209 | } 210 | 211 | .fileType { 212 | font-weight: 700; 213 | color: #E91E63; 214 | } 215 | } 216 | 217 | 218 | 219 | .fileNum { 220 | text-align: center; 221 | font-size: 1.8rem; 222 | } 223 | 224 | 225 | .fileContent { 226 | margin-bottom: 10px; 227 | } 228 | 229 | pre.fileCode { 230 | text-align: left; 231 | font-size: 1.2rem; 232 | line-height: 1.2; 233 | background: #111; 234 | padding: 5px; 235 | code { 236 | color: #fafafa; 237 | word-break: break-all; 238 | white-space: pre-wrap; 239 | } 240 | } 241 | 242 | p.fileMeta { 243 | font-size: 1.2rem; 244 | color: #757575; 245 | margin: 0; 246 | } 247 | p.fileDate { 248 | margin: 5px 0 0; 249 | font-size: 1.3rem; 250 | } 251 | 252 | footer.footerdetails { 253 | text-align: center; 254 | margin-top: 25px; 255 | p { 256 | margin: .5rem 0 .3rem; 257 | a { 258 | color: #F06292; 259 | text-decoration: none; 260 | } 261 | } 262 | } 263 | 264 | .removeAll { 265 | margin-bottom: 2rem; 266 | } 267 | 268 | 269 | -------------------------------------------------------------------------------- /assets/scripts/components/file_search.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import * as actions from '../actions'; 4 | 5 | class FileSearch extends Component { 6 | 7 | constructor(props) { 8 | super(props) 9 | this.state = { 10 | searchType: 'all', 11 | all: true, 12 | images: false, 13 | snippets: false, 14 | gdocs: false, 15 | zips: false, 16 | pdfs: false, 17 | fileList: 0 18 | } 19 | } 20 | 21 | getFiles() { 22 | let token = this.props.authData.token; 23 | let fileString, userID; 24 | if (this.props.profile.user.is_admin === false) { 25 | userID = this.props.authData.profile.id 26 | } else { 27 | userID = this.state.searchType; 28 | } 29 | if (this.state.all !== true) { 30 | let fileTypes = []; 31 | if(this.state.images) 32 | fileTypes.push('images') 33 | if(this.state.gdocs) 34 | fileTypes.push('gdocs') 35 | if(this.state.pdfs) 36 | fileTypes.push('pdfs') 37 | if(this.state.snippets) 38 | fileTypes.push('snippets') 39 | if(this.state.zips) 40 | fileTypes.push('zips') 41 | fileString = fileTypes.join(); 42 | } else { 43 | fileString = 'all' 44 | } 45 | this.props.fetchFiles(token, fileString, userID); 46 | } 47 | 48 | handleWhoChange(e) { 49 | this.setState({searchType: e.target.value}) 50 | } 51 | 52 | 53 | handleClick(e) { 54 | let type = e.target.value 55 | if (type !== 'all') { 56 | this.setState({ 57 | all: false, 58 | [type]: this.state[type] ? false : true 59 | }) 60 | } else { 61 | this.setState({ 62 | images: false, 63 | snippets: false, 64 | gdocs: false, 65 | zips: false, 66 | pdfs: false, 67 | all: true 68 | }) 69 | } 70 | } 71 | 72 | render() { 73 | let whoFiles = null, 74 | profileData = this.props.profile; 75 | if (typeof profileData !== 'undefined') { 76 | if (profileData.user.is_admin) { 77 | whoFiles = ( 78 |
79 | 80 | 84 |
85 | ) 86 | } 87 | } 88 | let fileDisplay = null; 89 | if (typeof this.props.files.fileList !== 'undefined' && this.props.files.fileList.length > 0) { 90 | fileDisplay =

You've got {this.props.files.fileList.length} files

91 | } else if (typeof this.props.files.fileList !== 'undefined' && this.props.files.fileList.length === 0) { 92 | fileDisplay =

No files! Search again for some more!

93 | } 94 | return ( 95 | 171 | ) 172 | } 173 | 174 | } 175 | 176 | function mapStateToProps(state) { 177 | return { 178 | authData: state.auth.profile, 179 | profile: state.profileInfo.data, 180 | files: state.files 181 | } 182 | } 183 | 184 | export default connect(mapStateToProps, actions)(FileSearch); -------------------------------------------------------------------------------- /public/styles/main.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.clearfix:after{content:"";display:table;clear:both}html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}html{font-size:62.5%}body{font-size:15px;font-size:1.5rem;line-height:1.428;font-family:poppins;sans-serif,:300}h1{font-size:3.157em}h2{font-size:1.9em}h3{font-size:1.3em}h4{font-size:1.333em}h1,h2,h3,h4,h5,h6{font-family:inherit;color:inherit;line-height:1.2;letter-spacing:-.04em;font-family:poppins;sans-serif,:600}h1,h2,h3{margin-top:10px;margin-bottom:10px}p{font-size:1em;line-height:1.428}dl,ol,ul{margin-top:0;margin-bottom:10px}dl:last-child,ol:last-child,ul:last-child{margin-bottom:0}fieldset,input,select,textarea{box-sizing:border-box;margin-top:0;margin-bottom:0;font-size:15px;font-size:1.5rem;font-family:inherit}.input{padding:2px 10px;background:#fafafa}.input,.dropdown{width:100%;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-size:14px;font-size:1.4rem;color:#111;border:3px solid #111;box-shadow:0 0 10px rgba(0,0,0,.3)}.dropdown{padding:5px 10px;background:#fafafa url(../images/dropdown.svg) no-repeat 95%;border-radius:0}label{vertical-align:middle}.login,button.login{display:inline-block;text-decoration:none}.login,button.login,button.deleteAll{font-size:20px;font-size:2rem;background:#111;border:0;padding:10px 30px;color:#fff}button.deleteAll{-webkit-transition:all .3s;transition:all .3s;box-shadow:0 0 10px rgba(0,0,0,.3)}button.deleteAll:hover{background:#e91e63}button.search{font-size:20px;font-size:2rem;background:#111;width:100%;color:#fff;font-weight:300;border:0;padding:10px 30px;box-shadow:0 0 10px rgba(0,0,0,.3);-webkit-transition:all .8s;transition:all .8s}button.search:focus{outline:0}button.search:hover{background:#333}button.deleteFile{border:0;background:#111;display:inline-block;padding:10px 30px;color:#fff;-webkit-transition:all .3s;transition:all .3s}button.deleteFile:focus{outline:0}button.deleteFile:hover{background:#e91e63}body{min-height:100vh;background:#fafafa}img{max-width:100%}.wrapper{margin:0 auto;max-width:980px}header.home-intro{text-align:center;padding:200px;background:#651fff;border-bottom:30px solid #111;box-shadow:0 2px 25px rgba(0,0,0,.3)}header.home-intro h1{font-size:70px;font-size:7rem;color:#fafafa;margin:0;display:inline-block;line-height:1;padding:8px 20px 3px;border:7px solid #111;box-shadow:0 0 10px rgba(0,0,0,.1)}header.home-intro p.lead{color:#fff;font-size:18px;font-size:1.8rem}section.content{padding:150px 0}section.content .wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}section.content .rightcontent img{box-shadow:0 0 10px rgba(0,0,0,.1)}section.content .leftcontent{margin-right:50px}section.content .leftcontent p{line-height:1.7}section.content .leftcontent p a{text-decoration:none;color:#651fff}section.faq{background:#eee;padding:150px 0}section.faq .questionContainer{margin-bottom:25px}section.faq .questionContainer p.question{font-weight:700;font-size:19px;font-size:1.9rem;display:inline-block;margin-bottom:6px;margin-bottom:.6rem}section.faq .questionContainer p.answer{margin-top:0;line-height:2;font-size:16px;font-size:1.6rem}section.faq .questionContainer p.answer a{font-weight:700;color:#651fff;text-decoration:none}footer.home{background:#111;padding:50px 0;text-align:center;color:#fafafa}footer.home a{text-decoration:none;color:#651fff}header.app-header{width:100%;top:0;left:0;padding:15px 25px;position:fixed;z-index:1;background:#fff;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;box-shadow:0 2px 25px rgba(0,0,0,.3)}header.app-header .intro{position:relative}header.app-header .intro h1{margin:0;display:inline-block;line-height:1;padding:8px 20px 3px;border:4px solid #000;margin-right:10px}.userProfile{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.userProfile p{font-size:18px;font-size:1.8rem}.userProfile img.profileImage{display:block;margin-left:15px}.userProfile .logout{display:inline-block;margin-left:15px;font-size:14px;font-size:1.4rem;text-decoration:none;padding:10px 30px;color:#fff;background:#111}section.fileDisplay{top:102px;height:-webkit-calc(90vh - 402px);height:calc(90vh - 402px);position:relative}aside.fileControl{position:fixed;width:350px;height:100%;background:#651fff;top:100px;padding:20px 25px 150px;color:#fff;overflow:auto}p.formTitle{font-size:25px;font-size:2.5rem;font-weight:700}p.fileSize{font-size:17px;font-size:1.7rem;font-weight:700}.fileTypeList{margin-bottom:20px}header.displayInfo{margin-bottom:20px;padding:0 20px 20px;border-bottom:3px solid #111}.check-row{margin:10px 0}.check-row label{display:inline-block;font-size:13px;font-size:1.3rem;margin-right:10px;font-weight:300;background:rgba(0,0,0,.7);padding:5px 7px 2px}.check-row input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;position:relative}.check-row input[type=checkbox]:before{content:"";border:3px solid #111;background:#fafafa;position:absolute;top:-17px;left:0;width:25px;height:25px}.check-row input[type=checkbox]:checked:after{content:"×";font-size:30px;font-size:3rem;position:absolute;color:#111;top:-26px;left:2px}.check-row input[type=checkbox]:focus{outline:0}.field{width:100%;margin:20px 0}.field label{font-size:12px;font-size:1.2rem;margin-bottom:5px;display:inline-block;padding:5px 7px 2px;font-weight:300;background:rgba(0,0,0,.7)}section.fileList{margin-left:350px;width:-webkit-calc(100% - 350px);width:calc(100% - 350px);padding:25px;position:relative}.noFiles{position:absolute;width:450px;top:50px;left:-webkit-calc(50% - 225px);left:calc(50% - 225px);height:-webkit-calc(100vh - 350px);height:calc(100vh - 350px);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;text-align:center}.noFiles .noFiles-display ol{text-align:left}.noFiles .noFiles-display ol li{margin-bottom:10px;margin-bottom:1rem}article.fileCard{width:31%;margin:0 1% 20px;background:#fff;box-shadow:0 0 10px rgba(0,0,0,.1);text-align:center;padding:20px}article.fileCard .previewImg{height:179px;background:#e0e0e0;overflow:hidden;margin-bottom:10px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-flow:row wrap;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}article.fileCard h3{word-break:break-all;font-weight:700}article.fileCard h3 a{color:#111;text-decoration:none}article.fileCard .fileType{font-weight:700;color:#e91e63}.fileNum{text-align:center;font-size:18px;font-size:1.8rem}.fileContent{margin-bottom:10px}pre.fileCode{text-align:left;font-size:12px;font-size:1.2rem;line-height:1.2;background:#111;padding:5px}pre.fileCode code{color:#fafafa;word-break:break-all;white-space:pre-wrap}p.fileMeta{font-size:12px;font-size:1.2rem;color:#757575;margin:0}p.fileDate{margin:5px 0 0;font-size:13px;font-size:1.3rem}footer.footerdetails{text-align:center;margin-top:25px}footer.footerdetails p{margin:5px 0 3px;margin:.5rem 0 .3rem}footer.footerdetails p a{color:#f06292;text-decoration:none}.removeAll{margin-bottom:20px;margin-bottom:2rem} 2 | /*# sourceMappingURL=main.css.map */ 3 | -------------------------------------------------------------------------------- /public/styles/main.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["partials/_fileForm.scss","utilities/_normalize.scss","main.css","utilities/_typography.scss","utilities/_tools.scss","utilities/_brand.scss","utilities/_form.scss","main.scss"],"names":[],"mappings":"AA+BA,iBC/BA,AD6DG,KC5DD,uBAAwB,AACxB,0BAA2B,AAC3B,6BAA+B,CAChC,AAED,KACE,QAAU,CACX,AAED,2FAaE,aAAe,CAChB,AAED,4BAIE,qBAAsB,AACtB,uBAAyB,CAC1B,AAED,sBACE,aAAc,AACd,QAAU,CACX,ACAD,kBDIE,YAAc,CACf,AAED,EACE,4BAA8B,CAC/B,AAED,iBAEE,SAAW,CACZ,AAED,YACE,wBAA0B,CAC3B,AAED,SAEE,eAAkB,CACnB,AAED,IACE,iBAAmB,CACpB,AAED,GACE,cAAe,AACf,cAAgB,CACjB,AAED,KACE,gBAAiB,AACjB,UAAY,CACb,AAED,MACE,aAAe,CAChB,AAED,QAEE,cAAe,AACf,cAAe,AACf,kBAAmB,AACnB,uBAAyB,CAC1B,AAED,IACE,SAAW,CACZ,AAED,IACE,aAAe,CAChB,AAED,IACE,QAAU,CACX,AAED,eACE,eAAiB,CAClB,AAED,OACE,eAAiB,CAClB,AAED,GAEE,uBAAwB,AACxB,QAAU,CACX,AAED,IACE,aAAe,CAChB,AAED,kBAIE,sBAAkC,AAClC,aAAe,CAChB,AAED,sCAKE,cAAe,AACf,aAAc,AACd,QAAU,CACX,AAED,OACE,gBAAkB,CACnB,AAED,cAEE,mBAAqB,CACtB,AAED,oEAIE,0BAA2B,AAC3B,cAAgB,CACjB,AAED,sCAEE,cAAgB,CACjB,AAED,iDAEE,SAAU,AACV,SAAW,CACZ,AAED,MACE,kBAAoB,CACrB,AAED,uCAEE,sBAAuB,AACvB,SAAW,CACZ,AACD,4FAEE,WAAa,CACd,AAED,mBACE,6BAA8B,AAG9B,sBAAwB,CACzB,AAED,+FAEE,uBAAyB,CAC1B,AAED,SACE,wBAA0B,AAC1B,aAAc,AACd,0BAA4B,CAC7B,AAED,OACE,SAAU,AACV,SAAW,CACZ,AAED,SACE,aAAe,CAChB,AAED,SACE,eAAkB,CACnB,AAED,MACE,yBAA0B,AAC1B,gBAAkB,CACnB,AAED,MAEE,SAAW,CACZ,AAED,gBAGM,WAAY,AACZ,cAAe,AACf,UAAY,CACf,AAGH,KACE,qBAAuB,CACxB,AAED,iBACE,kBAAoB,CACrB,AExOD,KAAO,eAAiB,CAAI,AAG5B,KACC,eAAA,AANe,iBAAA,AAOf,kBAAmB,ACLlB,oBCDqB,ADCrB,eCAe,CFOhB,AAED,GAAK,iBAAmB,CAAI,AAC5B,GAAK,eAAiB,CAAI,AAC1B,GAAK,eAAiB,CAAI,AAC1B,GAAK,iBAAmB,CAAI,AAE5B,kBAAyB,oBAAqB,AAG7C,cAAe,AACf,gBAAiB,AACjB,sBAAuB,ACnBtB,oBCIqB,ADJrB,eCKe,CFSiC,AASlD,SACC,gBAAiB,AACjB,kBAAoB,CACpB,AAED,EACC,cAAe,AACf,iBAAmB,CACnB,AAED,SACC,aAAc,AACd,kBAAoB,CAIpB,AAND,0CAIE,eAAiB,CACjB,AGxCF,+BAIC,sBAAuB,AACvB,aAAc,AACd,gBAAiB,AACjB,eAAA,AAAkB,iBAAA,AAClB,mBAAqB,CAErB,AAED,OAIC,iBAAkB,AAGlB,kBAAoB,CAEpB,AAED,iBAVC,WAAY,AACZ,wBAAA,AAAiB,qBAAjB,AAAiB,gBAAA,AACjB,eAAA,AAAkB,iBAAA,AAElB,WAAY,AACZ,sBAAuB,AAEvB,kCAAyB,CAG1B,AAUC,UANA,iBAAkB,AAElB,6DAAsE,AAEtE,eAAiB,CAEjB,AAED,MACC,qBAAuB,CACvB,AAED,oBACC,qBAAsB,AAMtB,oBAAsB,CACtB,AAED,qCARC,eAAA,AAAgB,eAAA,AAChB,gBAAiB,AACjB,SAAU,AACV,kBAAmB,AACnB,UAAa,CAId,AAWC,iBALA,2BAAA,AAAoB,mBAAA,AACpB,kCAAyB,CAIzB,AAXD,uBASE,kBAAoB,CACpB,AAGF,cACC,eAAA,AAAgB,eAAA,AAChB,gBAAiB,AACjB,WAAY,AACZ,WAAa,AACb,gBAAiB,AACjB,SAAU,AACV,kBAAmB,AACnB,mCAAyB,AACzB,2BAAA,AAAoB,kBAAA,CAOpB,AAhBD,oBAWE,SAAW,CACX,AAZF,oBAcE,eAAiB,CACjB,AAGF,kBACC,SAAU,AACV,gBAAiB,AACjB,qBAAsB,AACtB,kBAAmB,AACnB,WAAa,AACb,2BAAA,AAAoB,kBAAA,CAOpB,AAbD,wBAQE,SAAW,CACX,AATF,wBAWE,kBAAoB,CACpB,ACpFF,KACC,iBAAkB,AAClB,kBAAoB,CACpB,AAED,IACC,cAAgB,CAChB,AAED,SACC,cAAe,AACf,eAAiB,CACjB,AAED,kBACC,kBAAmB,AACnB,cAAe,AACf,mBAAoB,AACpB,8BAA+B,AAC/B,oCAAA,CAeA,AApBD,qBAOE,eAAA,AAAgB,eAAA,AAChB,cAAe,AACf,SAAU,AACV,qBAAsB,AACrB,cAAe,AACf,qBAAsB,AACtB,sBAAuB,AACvB,kCAAA,CACD,AAfF,yBAiBE,WAAa,AACb,eAAA,AAAkB,gBAAA,CAClB,AAGF,gBACC,eAAiB,CAiBjB,AAlBD,yBAGE,oBAAA,AAAc,qBAAd,AAAc,oBAAd,AAAc,YAAA,CACd,AAJF,kCAME,kCAAA,CACA,AAPF,6BASE,iBAAmB,CAQnB,AAjBF,+BAWG,eAAiB,CAKjB,AAhBH,iCAaI,qBAAsB,AACtB,aAAe,CACf,AAKJ,YACC,gBAAoB,AACpB,eAAiB,CAoBjB,AAtBD,+BAIE,kBAAoB,CAiBpB,AArBF,0CAMG,gBAAiB,AACjB,eAAA,AAAkB,iBAAA,AAClB,qBAAsB,AACtB,kBAAA,AAAqB,mBAAA,CACrB,AAVH,wCAYG,aAAc,AACd,cAAe,AACf,eAAA,AAAkB,gBAAA,CAMlB,AApBH,0CAgBI,gBAAiB,AACjB,cAAe,AACf,oBAAsB,CACtB,AAKJ,YACC,gBAAiB,AACjB,eAAgB,AAChB,kBAAmB,AACnB,aAAe,CAKf,AATD,cAME,qBAAsB,AACtB,aAAe,CACf,AAOF,kBACC,WAAY,AACZ,MAAO,AACP,OAAQ,AACR,kBAAmB,AACnB,eAAgB,AAChB,UAAW,AACX,gBAAkB,AAClB,oBAAA,AAAc,qBAAd,AAAc,oBAAd,AAAc,aAAA,AACd,yBAAA,AAAoB,2BAApB,AAAoB,sBAApB,AAAoB,mBAAA,AACpB,yBAAA,AAA+B,sCAA/B,AAA+B,sBAA/B,AAA+B,8BAAA,AAC/B,oCAAA,CAYA,AAvBD,yBAaE,iBAAmB,CASnB,AAtBF,4BAeG,SAAU,AACV,qBAAsB,AACrB,cAAe,AACf,qBAAsB,AACtB,sBAAwB,AACxB,iBAAmB,CACpB,AAIH,aACC,oBAAA,AAAc,qBAAd,AAAc,oBAAd,AAAc,aAAA,AACd,yBAAA,AAAoB,2BAApB,AAAoB,sBAApB,AAAoB,kBAAA,CAiBpB,AAnBD,eAIE,eAAA,AAAkB,gBAAA,CAClB,AALF,8BAOE,cAAe,AACf,gBAAkB,CAClB,AATF,qBAWE,qBAAsB,AACtB,iBAAkB,AAClB,eAAA,AAAkB,iBAAA,AAClB,qBAAsB,AACtB,kBAAmB,AACnB,WAAa,AACb,eAAiB,CACjB,AAGF,oBACC,UAAW,AACX,kCAAA,0BAAA,AACA,iBAAmB,CACnB,APzJD,kBACC,eAAgB,AAChB,YAAa,AACb,YAAa,AACb,mBAAoB,AACpB,UAAW,AACX,wBAA8B,AAC9B,WAAa,AACb,aAAe,CACf,AAED,YACC,eAAA,AAAkB,iBAAA,AAClB,eAAiB,CACjB,AAED,WACC,eAAA,AAAkB,iBAAA,AAClB,eAAiB,CACjB,AAED,cACC,kBAAoB,CACpB,AAED,mBACC,mBAAoB,AACpB,oBAAqB,AACrB,4BAA8B,CAC9B,AAED,WACC,aAAe,CAkCf,AAnCD,iBAGE,qBAAsB,AACtB,eAAA,AAAkB,iBAAA,AAClB,kBAAmB,AACnB,gBAAiB,AACjB,0BAAgB,AAChB,mBAAqB,CACrB,AATF,gCAWE,wBAAA,AAAiB,qBAAjB,AAAiB,gBAAA,AACjB,iBAAmB,CAsBnB,AAlCF,uCAcG,WAAY,AACZ,sBAAuB,AACvB,mBAAoB,AACpB,kBAAmB,AACnB,UAAW,AACX,OAAQ,AACR,WAAY,AACZ,WAAa,CACb,AAtBH,8CAwBG,YAAc,AACd,eAAA,AAAgB,eAAA,AAChB,kBAAmB,AACnB,WAAY,AACZ,UAAW,AACX,QAAU,CACV,AA9BH,sCAgCG,SAAW,CACX,AAIH,OACC,WAAY,AACZ,aAAe,CASf,AAXD,aAIE,eAAA,AAAkB,iBAAA,AAClB,kBAAmB,AACnB,qBAAsB,AACtB,oBAAqB,AACrB,gBAAiB,AACjB,yBAAgB,CAChB,AO+EF,iBACC,kBAAmB,AACnB,iCAAA,yBAAA,AACA,aAAc,AACd,iBAAmB,CACnB,AAED,SACC,kBAAmB,AACnB,YAAa,AACb,SAAU,AACV,+BAAA,uBAAA,AACA,mCAAA,2BAAA,AACA,oBAAA,AAAc,qBAAd,AAAc,oBAAd,AAAc,aAAA,AACd,wBAAA,AAAwB,+BAAxB,AAAwB,qBAAxB,AAAwB,uBAAA,AACxB,yBAAA,AAAoB,2BAApB,AAAoB,sBAApB,AAAoB,mBAAA,AACpB,iBAAmB,CASnB,AAlBD,6BAYG,eAAiB,CAIjB,AAhBH,gCAcI,mBAAA,AAAoB,kBAAA,CACpB,AAKJ,iBACC,UAAW,AACX,iBAAqB,AACrB,gBAAkB,AAClB,mCAAA,AACA,kBAAmB,AACnB,YAAc,CAwBd,AA9BD,6BAQE,aAAc,AACd,mBAAoB,AACpB,gBAAiB,AACjB,mBAAoB,AACpB,oBAAA,AAAc,qBAAd,AAAc,oBAAd,AAAc,aAAA,AACd,2BAAA,AAAoB,uBAApB,AAAoB,mBAAA,AACpB,yBAAA,AAAoB,2BAApB,AAAoB,sBAApB,AAAoB,mBAAA,AACpB,wBAAA,AAAwB,+BAAxB,AAAwB,qBAAxB,AAAwB,sBAAA,CACxB,AAhBF,oBAkBE,qBAAsB,AACtB,eAAiB,CAKjB,AAxBF,sBAqBG,WAAY,AACZ,oBAAsB,CACtB,AAvBH,2BA2BE,gBAAiB,AACjB,aAAe,CACf,AAKF,SACC,kBAAmB,AACnB,eAAA,AAAkB,gBAAA,CAClB,AAGD,aACC,kBAAoB,CACpB,AAED,aACC,gBAAiB,AACjB,eAAA,AAAkB,iBAAA,AAClB,gBAAiB,AACjB,gBAAiB,AACjB,WAAa,CAMb,AAXD,kBAOE,cAAe,AACf,qBAAsB,AACtB,oBAAsB,CACtB,AAGF,WACC,eAAA,AAAkB,iBAAA,AAClB,cAAe,AACf,QAAU,CACV,AACD,WACC,eAAgB,AAChB,eAAA,AAAkB,gBAAA,CAClB,AAED,qBACC,kBAAmB,AACnB,eAAiB,CAQjB,AAVD,uBAIE,iBAAA,AAAsB,oBAAA,CAKtB,AATF,yBAMG,cAAe,AACf,oBAAsB,CACtB,AAIH,WACC,mBAAA,AAAoB,kBAAA,CACpB","file":"main.css","sourcesContent":["aside.fileControl {\n\tposition: fixed;\n\twidth: 350px;\n\theight: 100%;\n\tbackground: #651FFF;\n\ttop: 100px;\n\tpadding: 20px 25px 150px 25px;\n\tcolor: white;\n\toverflow: auto;\n}\n\np.formTitle {\n\tfont-size: 2.5rem;\n\tfont-weight: 700;\n}\n\np.fileSize {\n\tfont-size: 1.7rem;\n\tfont-weight: 700;\n}\n\n.fileTypeList {\n\tmargin-bottom: 20px;\n}\n\nheader.displayInfo {\n\tmargin-bottom: 20px;\n\tpadding: 0 20px 20px;\n\tborder-bottom: 3px solid #111;\n}\n\n.check-row {\n\tmargin: 10px 0;\n\tlabel {\n\t\tdisplay: inline-block;\n\t\tfont-size: 1.3rem;\n\t\tmargin-right: 10px;\n\t\tfont-weight: 300;\n\t\tbackground: rgba(0,0,0,.7);\n\t\tpadding: 5px 7px 2px;\n\t}\n\tinput[type=checkbox] {\n\t\tappearance: none;\n\t\tposition: relative;\n\t\t&::before {\n\t\t\tcontent: \"\";\n\t\t\tborder: 3px solid #111;\n\t\t\tbackground: #fafafa;\n\t\t\tposition: absolute;\n\t\t\ttop: -17px;\n\t\t\tleft: 0;\n\t\t\twidth: 25px;\n\t\t\theight: 25px;\n\t\t}\n\t\t&:checked::after {\n\t\t\tcontent: \"×\";\n\t\t\tfont-size: 3rem;\n\t\t\tposition: absolute;\n\t\t\tcolor: #111;\n\t\t\ttop: -26px;\n\t\t\tleft: 2px;\n\t\t}\n\t\t&:focus {\n\t\t\toutline: 0;\n\t\t}\n\t}\n}\n\n.field {\n\twidth: 100%;\n\tmargin: 20px 0;\n\tlabel {\n\t\tfont-size: 1.2rem;\n\t\tmargin-bottom: 5px;\n\t\tdisplay: inline-block;\n\t\tpadding: 5px 7px 2px;\n\t\tfont-weight: 300;\n\t\tbackground: rgba(0,0,0,.7);\n\t}\n}\n","html {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\n\nbody {\n margin: 0;\n}\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; /* 1 */\n vertical-align: baseline; /* 2 */\n}\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n[hidden],\ntemplate {\n display: none;\n}\n\na {\n background-color: transparent;\n}\n\na:active,\na:hover {\n outline: 0;\n}\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\nb,\nstrong {\n font-weight: bold;\n}\n\ndfn {\n font-style: italic;\n}\n\nh1 {\n font-size: 2em;\n margin: .67em 0;\n}\n\nmark {\n background: #ff0;\n color: #000;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -.5em;\n}\n\nsub {\n bottom: -.25em;\n}\n\nimg {\n border: 0;\n}\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\nfigure {\n margin: 1em 40px;\n}\n\nhr {\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\n\npre {\n overflow: auto;\n}\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; /* 1 */\n font: inherit; /* 2 */\n margin: 0; /* 3 */\n}\n\nbutton {\n overflow: visible;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; /* 2 */\n cursor: pointer; /* 3 */\n}\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\ninput {\n line-height: normal;\n}\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n -moz-box-sizing: content-box;\n -webkit-box-sizing: content-box; /* 2 */\n box-sizing: content-box;\n}\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: .35em .625em .75em;\n}\n\nlegend {\n border: 0; /* 1 */\n padding: 0; /* 2 */\n}\n\ntextarea {\n overflow: auto;\n}\n\noptgroup {\n font-weight: bold;\n}\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n\n.clearfix,\n%clearfix {\n &::after {\n content: \"\";\n display: table;\n clear: both;\n }\n}\n\nhtml {\n box-sizing: border-box;\n}\n\n*, *::before, *::after {\n box-sizing: inherit;\n}","@charset \"UTF-8\";\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%; }\n\nbody {\n margin: 0; }\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block; }\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n /* 1 */\n vertical-align: baseline;\n /* 2 */ }\n\naudio:not([controls]) {\n display: none;\n height: 0; }\n\n[hidden],\ntemplate {\n display: none; }\n\na {\n background-color: transparent; }\n\na:active,\na:hover {\n outline: 0; }\n\nabbr[title] {\n border-bottom: 1px dotted; }\n\nb,\nstrong {\n font-weight: bold; }\n\ndfn {\n font-style: italic; }\n\nh1 {\n font-size: 2em;\n margin: .67em 0; }\n\nmark {\n background: #ff0;\n color: #000; }\n\nsmall {\n font-size: 80%; }\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline; }\n\nsup {\n top: -.5em; }\n\nsub {\n bottom: -.25em; }\n\nimg {\n border: 0; }\n\nsvg:not(:root) {\n overflow: hidden; }\n\nfigure {\n margin: 1em 40px; }\n\nhr {\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0; }\n\npre {\n overflow: auto; }\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em; }\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n /* 1 */\n font: inherit;\n /* 2 */\n margin: 0;\n /* 3 */ }\n\nbutton {\n overflow: visible; }\n\nbutton,\nselect {\n text-transform: none; }\n\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n /* 2 */\n cursor: pointer;\n /* 3 */ }\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default; }\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0; }\n\ninput {\n line-height: normal; }\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n /* 1 */\n padding: 0;\n /* 2 */ }\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto; }\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n /* 1 */\n -moz-box-sizing: content-box;\n -webkit-box-sizing: content-box;\n /* 2 */\n box-sizing: content-box; }\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none; }\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: .35em .625em .75em; }\n\nlegend {\n border: 0;\n /* 1 */\n padding: 0;\n /* 2 */ }\n\ntextarea {\n overflow: auto; }\n\noptgroup {\n font-weight: bold; }\n\ntable {\n border-collapse: collapse;\n border-spacing: 0; }\n\ntd,\nth {\n padding: 0; }\n\n.clearfix::after {\n content: \"\";\n display: table;\n clear: both; }\n\nhtml {\n box-sizing: border-box; }\n\n*, *::before, *::after {\n box-sizing: inherit; }\n\nhtml {\n font-size: 62.5%; }\n\nbody {\n font-size: 1.5rem;\n line-height: 1.428;\n font-family: \"poppins\";\n sans-serif, font-weight: 300; }\n\nh1 {\n font-size: 3.157em; }\n\nh2 {\n font-size: 1.9em; }\n\nh3 {\n font-size: 1.3em; }\n\nh4 {\n font-size: 1.333em; }\n\nh1, h2, h3, h4, h5, h6 {\n font-family: inherit; }\n\nh1, h2, h3, h4, h5, h6 {\n color: inherit;\n line-height: 1.2;\n letter-spacing: -.04em;\n font-family: \"poppins\";\n sans-serif, font-weight: 600; }\n\nh1, h2, h3 {\n margin-top: 10px;\n margin-bottom: 10px; }\n\np {\n font-size: 1em;\n line-height: 1.428; }\n\nol, ul, dl {\n margin-top: 0;\n margin-bottom: 10px; }\n ol:last-child, ul:last-child, dl:last-child {\n margin-bottom: 0; }\n\ninput,\nselect,\ntextarea,\nfieldset {\n box-sizing: border-box;\n margin-top: 0;\n margin-bottom: 0;\n font-size: 1.5rem;\n font-family: inherit; }\n\n.input {\n width: 100%;\n appearance: none;\n font-size: 1.4rem;\n padding: 2px 10px;\n color: #111;\n border: 3px solid #111;\n background: #fafafa;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); }\n\n.dropdown {\n width: 100%;\n appearance: none;\n font-size: 1.4rem;\n padding: 5px 10px;\n color: #111;\n background: #fafafa url(\"../images/dropdown.svg\") no-repeat 95% center;\n border: 3px solid #111;\n border-radius: 0;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); }\n\nlabel {\n vertical-align: middle; }\n\nbutton.login, .login {\n display: inline-block;\n font-size: 2rem;\n background: #111;\n border: 0;\n padding: 10px 30px;\n color: white;\n text-decoration: none; }\n\nbutton.deleteAll {\n font-size: 2rem;\n background: #111;\n border: 0;\n padding: 10px 30px;\n color: white;\n transition: all .3s;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); }\n button.deleteAll:hover {\n background: #E91E63; }\n\nbutton.search {\n font-size: 2rem;\n background: #111;\n width: 100%;\n color: white;\n font-weight: 300;\n border: 0;\n padding: 10px 30px;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n transition: all .8s; }\n button.search:focus {\n outline: 0; }\n button.search:hover {\n background: #333; }\n\nbutton.deleteFile {\n border: 0;\n background: #111;\n display: inline-block;\n padding: 10px 30px;\n color: white;\n transition: all .3s; }\n button.deleteFile:focus {\n outline: 0; }\n button.deleteFile:hover {\n background: #E91E63; }\n\n@lost flexbox flex;\nbody {\n min-height: 100vh;\n background: #fafafa; }\n\nimg {\n max-width: 100%; }\n\n.wrapper {\n margin: 0 auto;\n max-width: 980px; }\n\nheader.home-intro {\n text-align: center;\n padding: 200px;\n background: #651FFF;\n border-bottom: 30px solid #111;\n box-shadow: 0 2px 25px rgba(0, 0, 0, 0.3); }\n header.home-intro h1 {\n font-size: 7rem;\n color: #fafafa;\n margin: 0;\n display: inline-block;\n line-height: 1;\n padding: 8px 20px 3px;\n border: 7px solid #111;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); }\n header.home-intro p.lead {\n color: white;\n font-size: 1.8rem; }\n\nsection.content {\n padding: 150px 0; }\n section.content .wrapper {\n display: flex; }\n section.content .rightcontent img {\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); }\n section.content .leftcontent {\n margin-right: 50px; }\n section.content .leftcontent p {\n line-height: 1.7; }\n section.content .leftcontent p a {\n text-decoration: none;\n color: #651FFF; }\n\nsection.faq {\n background: #EEEEEE;\n padding: 150px 0; }\n section.faq .questionContainer {\n margin-bottom: 25px; }\n section.faq .questionContainer p.question {\n font-weight: 700;\n font-size: 1.9rem;\n display: inline-block;\n margin-bottom: .6rem; }\n section.faq .questionContainer p.answer {\n margin-top: 0;\n line-height: 2;\n font-size: 1.6rem; }\n section.faq .questionContainer p.answer a {\n font-weight: 700;\n color: #651FFF;\n text-decoration: none; }\n\nfooter.home {\n background: #111;\n padding: 50px 0;\n text-align: center;\n color: #fafafa; }\n footer.home a {\n text-decoration: none;\n color: #651FFF; }\n\n/*===========================================\n= Structural Partials =\n===========================================*/\nheader.app-header {\n width: 100%;\n top: 0;\n left: 0;\n padding: 15px 25px;\n position: fixed;\n z-index: 2;\n background: white;\n display: flex;\n align-items: center;\n justify-content: space-between;\n box-shadow: 0 2px 25px rgba(0, 0, 0, 0.3); }\n header.app-header .intro {\n position: relative; }\n header.app-header .intro h1 {\n margin: 0;\n display: inline-block;\n line-height: 1;\n padding: 8px 20px 3px;\n border: 4px solid black;\n margin-right: 10px; }\n\n.userProfile {\n display: flex;\n align-items: center; }\n .userProfile p {\n font-size: 1.8rem; }\n .userProfile img.profileImage {\n display: block;\n margin-left: 15px; }\n .userProfile .logout {\n display: inline-block;\n margin-left: 15px;\n font-size: 1.4rem;\n text-decoration: none;\n padding: 10px 30px;\n color: white;\n background: #111; }\n\nsection.fileDisplay {\n top: 102px;\n height: calc(90vh - 402px);\n position: relative; }\n\naside.fileControl {\n position: fixed;\n width: 350px;\n height: 100%;\n background: #651FFF;\n top: 100px;\n padding: 20px 25px 150px 25px;\n color: white;\n overflow: auto; }\n\np.formTitle {\n font-size: 2.5rem;\n font-weight: 700; }\n\np.fileSize {\n font-size: 1.7rem;\n font-weight: 700; }\n\n.fileTypeList {\n margin-bottom: 20px; }\n\nheader.displayInfo {\n margin-bottom: 20px;\n padding: 0 20px 20px;\n border-bottom: 3px solid #111; }\n\n.check-row {\n margin: 10px 0; }\n .check-row label {\n display: inline-block;\n font-size: 1.3rem;\n margin-right: 10px;\n font-weight: 300;\n background: rgba(0, 0, 0, 0.7);\n padding: 5px 7px 2px; }\n .check-row input[type=checkbox] {\n appearance: none;\n position: relative; }\n .check-row input[type=checkbox]::before {\n content: \"\";\n border: 3px solid #111;\n background: #fafafa;\n position: absolute;\n top: -17px;\n left: 0;\n width: 25px;\n height: 25px; }\n .check-row input[type=checkbox]:checked::after {\n content: \"×\";\n font-size: 3rem;\n position: absolute;\n color: #111;\n top: -26px;\n left: 2px; }\n .check-row input[type=checkbox]:focus {\n outline: 0; }\n\n.field {\n width: 100%;\n margin: 20px 0; }\n .field label {\n font-size: 1.2rem;\n margin-bottom: 5px;\n display: inline-block;\n padding: 5px 7px 2px;\n font-weight: 300;\n background: rgba(0, 0, 0, 0.7); }\n\nsection.fileList {\n margin-left: 350px;\n width: calc(100% - 350px);\n padding: 25px;\n position: relative; }\n\n.noFiles {\n position: absolute;\n width: 450px;\n top: 50px;\n left: calc(50% - 225px);\n height: calc(100vh - 350px);\n display: flex;\n justify-content: center;\n align-items: center;\n text-align: center; }\n .noFiles .noFiles-display ol {\n text-align: left; }\n .noFiles .noFiles-display ol li {\n margin-bottom: 1rem; }\n\narticle.fileCard {\n width: 31%;\n margin: 0 1% 20px 1%;\n background: white;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n text-align: center;\n padding: 20px; }\n article.fileCard .previewImg {\n height: 179px;\n background: #E0E0E0;\n overflow: hidden;\n margin-bottom: 10px;\n display: flex;\n flex-flow: row wrap;\n align-items: center;\n justify-content: center; }\n article.fileCard h3 {\n word-break: break-all;\n font-weight: 700; }\n article.fileCard h3 a {\n color: #111;\n text-decoration: none; }\n article.fileCard .fileType {\n font-weight: 700;\n color: #E91E63; }\n\n.fileNum {\n text-align: center;\n font-size: 1.8rem; }\n\n.fileContent {\n margin-bottom: 10px; }\n\npre.fileCode {\n text-align: left;\n font-size: 1.2rem;\n line-height: 1.2;\n background: #111;\n padding: 5px; }\n pre.fileCode code {\n color: #fafafa;\n word-break: break-all;\n white-space: pre-wrap; }\n\np.fileMeta {\n font-size: 1.2rem;\n color: #757575;\n margin: 0; }\n\np.fileDate {\n margin: 5px 0 0;\n font-size: 1.3rem; }\n\nfooter.footerdetails {\n text-align: center;\n margin-top: 25px; }\n footer.footerdetails p {\n margin: .5rem 0 .3rem; }\n footer.footerdetails p a {\n color: #F06292;\n text-decoration: none; }\n\n.removeAll {\n margin-bottom: 2rem; }\n","$base-px: 1.5rem !default;\n\nhtml { font-size: 62.5%; }\n\n// 1.333 Perfect Fourth\nbody {\n\tfont-size: $base-px;\n\tline-height: 1.428;\n\t@include print-styles($body);\n}\n\nh1 { font-size: 3.157em; }\nh2 { font-size: 1.9em; }\nh3 { font-size: 1.3em; }\nh4 { font-size: 1.333em; }\n\nh1, h2, h3, h4, h5, h6 { font-family: inherit; }\n\nh1, h2, h3, h4, h5, h6 {\n\tcolor: inherit;\n\tline-height: 1.2;\n\tletter-spacing: -.04em;\n\t@include print-styles($headings)\n}\n\nh1, h2, h3 {\n\tmargin-top: 10px;\n\tmargin-bottom: 10px;\n}\n\np {\n\tfont-size: 1em;\n\tline-height: 1.428;\n}\n\nol, ul, dl {\n\tmargin-top: 0;\n\tmargin-bottom: 10px;\n\t&:last-child {\n\t\tmargin-bottom: 0;\n\t}\n}\n","@mixin print-styles($map) {\n\t@each $property, $value in $map {\n\t\t#{$property}: $value;\n\t}\n}\n\n@mixin bp($point) {\n @if $point == xl { // 1050px\n @media (max-width: 65.625rem) { @content; }\n }\n @else if $point == lg { // 900px\n @media (max-width: 56.25rem) { @content; }\n }\n @else if $point == md { // 768px\n @media (max-width: 48rem) { @content; }\n }\n @else if $point == sm { // 600px\n @media (max-width: 37.5rem) { @content; }\n }\n @else if $point == xs { // 400px\n @media (max-width: 25rem) { @content; }\n }\n}\n\n@mixin cf {\n\t*zoom: 1;\n\t&::before,\n\t&::after {\n\t\tdisplay: table;\n\t\tcontent: \"\";\n\t\tline-height: 0;\n\t}\n\t&::after {\n\t\tclear: both;\n\t}\n}\n\n// Hide text\n// ---------\n@mixin hide-text {\n\tfont: 0/0 a;\n\tcolor: transparent;\n\ttext-shadow: none;\n}","$body : (\n\tfont-family: \"poppins\", sans-serif, \n\tfont-weight: 300\n);\n\n$headings: (\n\tfont-family: \"poppins\", sans-serif, \n\tfont-weight: 600\n);\n\n$green: #62F1AC;\n\n// Sass\n","input,\nselect,\ntextarea,\nfieldset {\n\tbox-sizing: border-box;\n\tmargin-top: 0;\n\tmargin-bottom: 0;\n\tfont-size: 1.5rem;\n\tfont-family: inherit;\n\t// -webkit-appearance: none;\n}\n\n.input {\n\twidth: 100%;\n\tappearance: none;\n\tfont-size: 1.4rem;\n\tpadding: 2px 10px;\n\tcolor: #111;\n\tborder: 3px solid #111;\n\tbackground: #fafafa;\n\tbox-shadow: 0 0 10px rgba(0,0,0,.3);\n}\n\n.dropdown {\n\twidth: 100%;\n\tappearance: none;\n\tfont-size: 1.4rem;\n\tpadding: 5px 10px;\n\tcolor: #111;\n\tbackground: #fafafa url(\"../images/dropdown.svg\") no-repeat 95% center;\n\tborder: 3px solid #111;\n\tborder-radius: 0;\n\tbox-shadow: 0 0 10px rgba(0,0,0,.3);\n}\n\nlabel {\n\tvertical-align: middle;\n}\n\nbutton.login, .login {\n\tdisplay: inline-block;\n\tfont-size: 2rem;\n\tbackground: #111;\n\tborder: 0;\n\tpadding: 10px 30px;\n\tcolor: white;\n\ttext-decoration: none;\n}\n\nbutton.deleteAll {\n\tfont-size: 2rem;\n\tbackground: #111;\n\tborder: 0;\n\tpadding: 10px 30px;\n\tcolor: white;\n\ttransition: all .3s;\n\tbox-shadow: 0 0 10px rgba(0,0,0,.3);\n\t&:hover {\n\t\tbackground: #E91E63;\n\t}\n}\n\nbutton.search {\n\tfont-size: 2rem;\n\tbackground: #111;\n\twidth: 100%;\n\tcolor: white;\n\tfont-weight: 300;\n\tborder: 0;\n\tpadding: 10px 30px;\n\tbox-shadow: 0 0 10px rgba(0,0,0,.3);\n\ttransition: all .8s;\n\t&:focus {\n\t\toutline: 0;\n\t}\n\t&:hover {\n\t\tbackground: #333;\n\t}\n}\n\nbutton.deleteFile {\n\tborder: 0;\n\tbackground: #111;\n\tdisplay: inline-block;\n\tpadding: 10px 30px;\n\tcolor: white;\n\ttransition: all .3s;\n\t&:focus {\n\t\toutline: 0;\n\t}\n\t&:hover {\n\t\tbackground: #E91E63;\n\t}\n}","@import \"utilities/normalize\";\n@import \"utilities/brand\";\n@import \"utilities/tools\";\n@import \"utilities/typography\";\n@import \"utilities/form\";\n\n@lost flexbox flex;\n\nbody {\n\tmin-height: 100vh;\n\tbackground: #fafafa;\n}\n\nimg {\n\tmax-width: 100%;\n}\n\n.wrapper {\n\tmargin: 0 auto;\n\tmax-width: 980px;\n}\n\nheader.home-intro {\n\ttext-align: center;\n\tpadding: 200px;\n\tbackground: #651FFF;\n\tborder-bottom: 30px solid #111;\n\tbox-shadow: 0 2px 25px rgba(0,0,0,.3);\n\th1 {\n\t\tfont-size: 7rem;\n\t\tcolor: #fafafa;\n\t\tmargin: 0;\n\t\tdisplay: inline-block;\n\t line-height: 1;\n\t padding: 8px 20px 3px;\n\t border: 7px solid #111;\n\t box-shadow: 0 0 10px rgba(0,0,0, .1);\n\t}\n\tp.lead {\n\t\tcolor: white;\n\t\tfont-size: 1.8rem;\n\t}\n}\n\nsection.content {\n\tpadding: 150px 0;\n\t.wrapper {\n\t\tdisplay: flex;\n\t}\n\t.rightcontent img {\n\t\tbox-shadow: 0 0 10px rgba(0,0,0, .1);\n\t}\n\t.leftcontent {\n\t\tmargin-right: 50px;\n\t\tp {\n\t\t\tline-height: 1.7;\n\t\t\ta {\n\t\t\t\ttext-decoration: none;\n\t\t\t\tcolor: #651FFF;\n\t\t\t}\n\t\t}\n\t}\n}\n\nsection.faq {\n\tbackground: #EEEEEE;\n\tpadding: 150px 0;\n\t.questionContainer {\n\t\tmargin-bottom: 25px;\n\t\tp.question {\n\t\t\tfont-weight: 700;\n\t\t\tfont-size: 1.9rem;\n\t\t\tdisplay: inline-block;\n\t\t\tmargin-bottom: .6rem;\n\t\t}\n\t\tp.answer {\n\t\t\tmargin-top: 0;\n\t\t\tline-height: 2;\n\t\t\tfont-size: 1.6rem;\n\t\t\ta {\n\t\t\t\tfont-weight: 700;\n\t\t\t\tcolor: #651FFF;\n\t\t\t\ttext-decoration: none;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfooter.home {\n\tbackground: #111;\n\tpadding: 50px 0;\n\ttext-align: center;\n\tcolor: #fafafa;\n\ta {\n\t\ttext-decoration: none;\n\t\tcolor: #651FFF;\n\t}\n}\n\n/*===========================================\n= Structural Partials =\n===========================================*/\n\nheader.app-header {\n\twidth: 100%;\n\ttop: 0;\n\tleft: 0;\n\tpadding: 15px 25px;\n\tposition: fixed;\n\tz-index: 2;\n\tbackground: white;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tbox-shadow: 0 2px 25px rgba(0,0,0,.3);\n\t.intro {\n\t\tposition: relative;\n\t\th1 {\n\t\t\tmargin: 0;\n\t\t\tdisplay: inline-block;\n\t\t line-height: 1;\n\t\t padding: 8px 20px 3px;\n\t\t border: 4px solid black;\n\t\t margin-right: 10px;\n\t\t}\n\t}\n}\n\n.userProfile {\n\tdisplay: flex;\n\talign-items: center;\n\tp {\n\t\tfont-size: 1.8rem;\n\t}\n\timg.profileImage {\n\t\tdisplay: block;\n\t\tmargin-left: 15px;\n\t}\n\t.logout {\n\t\tdisplay: inline-block;\n\t\tmargin-left: 15px;\n\t\tfont-size: 1.4rem;\n\t\ttext-decoration: none;\n\t\tpadding: 10px 30px;\n\t\tcolor: white;\n\t\tbackground: #111;\n\t}\n}\n\nsection.fileDisplay {\n\ttop: 102px;\n\theight: calc(90vh - 402px);\n\tposition: relative;\n}\n\n@import \"partials/fileForm\";\n\nsection.fileList {\n\tmargin-left: 350px;\n\twidth: calc(100% - 350px);\n\tpadding: 25px;\n\tposition: relative;\n}\n\n.noFiles {\n\tposition: absolute;\n\twidth: 450px;\n\ttop: 50px;\n\tleft: calc(50% - 225px);\n\theight: calc(100vh - 350px);\n\tdisplay: flex;\n\tjustify-content: center;\n\talign-items: center;\n\ttext-align: center;\n\t.noFiles-display {\n\t\tol {\n\t\t\ttext-align: left;\n\t\t\tli {\n\t\t\t\tmargin-bottom: 1rem;\n\t\t\t}\n\t\t}\n\t}\n}\n\narticle.fileCard {\n\twidth: 31%;\n\tmargin: 0 1% 20px 1%;\n\tbackground: white;\n\tbox-shadow: 0 0 10px rgba(0,0,0, .1);\n\ttext-align: center;\n\tpadding: 20px;\n\t.previewImg {\n\t\theight: 179px;\n\t\tbackground: #E0E0E0;\n\t\toverflow: hidden;\n\t\tmargin-bottom: 10px;\n\t\tdisplay: flex;\n\t\tflex-flow: row wrap;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t}\n\th3 {\n\t\tword-break: break-all;\n\t\tfont-weight: 700;\n\t\ta {\n\t\t\tcolor: #111;\n\t\t\ttext-decoration: none;\n\t\t}\n\t}\n\t\n\t.fileType {\n\t\tfont-weight: 700;\n\t\tcolor: #E91E63;\n\t}\n}\n\n\n\n.fileNum {\n\ttext-align: center;\n\tfont-size: 1.8rem;\n}\n\n\n.fileContent {\n\tmargin-bottom: 10px;\n}\n\npre.fileCode {\n\ttext-align: left;\n\tfont-size: 1.2rem;\n\tline-height: 1.2;\n\tbackground: #111;\n\tpadding: 5px;\n\tcode {\n\t\tcolor: #fafafa;\n\t\tword-break: break-all;\n\t\twhite-space: pre-wrap;\n\t}\n}\n\np.fileMeta {\n\tfont-size: 1.2rem;\n\tcolor: #757575;\n\tmargin: 0;\n}\np.fileDate {\n\tmargin: 5px 0 0;\n\tfont-size: 1.3rem;\n}\n\nfooter.footerdetails {\n\ttext-align: center;\n\tmargin-top: 25px;\n\tp {\n\t\tmargin: .5rem 0 .3rem;\n\t\ta {\n\t\t\tcolor: #F06292;\n\t\t\ttext-decoration: none;\n\t\t}\n\t}\n}\n\n.removeAll {\n\tmargin-bottom: 2rem;\n}\n\n\n"],"sourceRoot":"/source/"} --------------------------------------------------------------------------------