chore: initial
This commit is contained in:
commit
a434670e5e
116
.gitignore
vendored
Normal file
116
.gitignore
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
18
app/.eslint.defaults.js
Normal file
18
app/.eslint.defaults.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
const config = {
|
||||
globals: {
|
||||
__non_webpack_require__: true,
|
||||
process: true,
|
||||
},
|
||||
rules: {
|
||||
'babel/object-curly-spacing': 'off',
|
||||
'brace-style': ['error', 'stroustrup'],
|
||||
'no-bitwise': ['error', {int32Hint: true}],
|
||||
'no-plusplus': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'padded-blocks': ['error', {classes: 'always'}],
|
||||
yoda: 'off',
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
3
app/.eslintrc.js
Normal file
3
app/.eslintrc.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = neutrino().eslintrc();
|
119
app/.gitignore
vendored
Normal file
119
app/.gitignore
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
/build
|
||||
/latus.yml
|
5
app/.mocharc.js
Normal file
5
app/.mocharc.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const neutrino = require('neutrino');
|
||||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'test';
|
||||
|
||||
module.exports = neutrino().mocha();
|
59
app/.neutrinorc.js
Normal file
59
app/.neutrinorc.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
require('dotenv/config');
|
||||
|
||||
const airbnbBase = require('@neutrinojs/airbnb-base');
|
||||
const clean = require('@neutrinojs/clean');
|
||||
const mocha = require('@neutrinojs/mocha');
|
||||
const node = require('@neutrinojs/node');
|
||||
const {EnvironmentPlugin} = require('webpack');
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
|
||||
module.exports = {
|
||||
options: {
|
||||
root: __dirname,
|
||||
},
|
||||
use: [
|
||||
airbnbBase({
|
||||
eslint: {
|
||||
cache: false,
|
||||
baseConfig: require('./.eslint.defaults'),
|
||||
},
|
||||
}),
|
||||
clean({
|
||||
cleanOnceBeforeBuildPatterns: ['**/*.hot-update.*'],
|
||||
}),
|
||||
mocha(),
|
||||
node(),
|
||||
(neutrino) => {
|
||||
neutrino.config
|
||||
.plugin('environment')
|
||||
.use(EnvironmentPlugin, [{
|
||||
SIDE: 'server',
|
||||
}]);
|
||||
neutrino.config
|
||||
.entry('index')
|
||||
.prepend('@latus/core/start');
|
||||
if ('production' !== neutrino.config.get('mode')) {
|
||||
neutrino.config
|
||||
.entry('index')
|
||||
.prepend('dotenv/config');
|
||||
neutrino.config
|
||||
.plugin('start-server')
|
||||
.tap((args) => {
|
||||
const options = args[0];
|
||||
const inspectArg = process.argv.find((arg) => -1 !== arg.indexOf('--inspect'));
|
||||
if (inspectArg) {
|
||||
options.nodeArgs.push(inspectArg);
|
||||
}
|
||||
const profArg = process.argv.find((arg) => -1 !== arg.indexOf('--prof'));
|
||||
if (profArg) {
|
||||
options.nodeArgs.push(profArg);
|
||||
}
|
||||
return args;
|
||||
});
|
||||
}
|
||||
neutrino.config
|
||||
.externals(nodeExternals({
|
||||
}));
|
||||
},
|
||||
],
|
||||
};
|
17
app/docker-compose.yml
Normal file
17
app/docker-compose.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
version: '2'
|
||||
services:
|
||||
|
||||
redis:
|
||||
image: redis:6
|
||||
ports:
|
||||
- 6380:6379
|
||||
|
||||
mysql:
|
||||
image: mysql:8
|
||||
command:
|
||||
- '--default-authentication-plugin=mysql_native_password'
|
||||
environment:
|
||||
- MYSQL_DATABASE=db
|
||||
- MYSQL_ROOT_PASSWORD=UNSAFE_DEV_PASSWORD
|
||||
ports:
|
||||
- 32342:3306
|
36
app/latus.default.yml
Normal file
36
app/latus.default.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
'@latus/core': {
|
||||
up: [
|
||||
'@latus/db',
|
||||
'@latus/redis',
|
||||
'@latus/http',
|
||||
'@latus/repl',
|
||||
],
|
||||
}
|
||||
'@latus/db': {
|
||||
docker: 'cached',
|
||||
}
|
||||
'@latus/http': {
|
||||
plugins: [
|
||||
'@latus/core',
|
||||
'@latus/socket',
|
||||
'@latus/react',
|
||||
],
|
||||
request: [
|
||||
'@latus/user/session',
|
||||
'@latus/user/passport',
|
||||
],
|
||||
}
|
||||
'@latus/react': {}
|
||||
'@latus/redis': {
|
||||
docker: 'cached',
|
||||
}
|
||||
'@latus/redis/session': {}
|
||||
'@latus/repl': {}
|
||||
'@latus/socket': {
|
||||
middleware: [
|
||||
'@latus/user/session',
|
||||
'@latus/user/passport',
|
||||
],
|
||||
}
|
||||
'@latus/user/passport': {}
|
||||
'@latus/user/session': {}
|
44
app/package.json
Normal file
44
app/package.json
Normal file
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "reddichat",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "webpack --mode production",
|
||||
"dev": "webpack --mode development",
|
||||
"forcelatus": "pkgs=$(find node_modules/@latus -maxdepth 1 -mindepth 1 -printf '@latus/%f '); yarn upgrade $pkgs",
|
||||
"lint": "eslint --cache --format codeframe --ext mjs,jsx,js src",
|
||||
"repl": "rlwrap -C qmp socat STDIO UNIX:$(ls /tmp/latus-*.sock | tail -n 1)",
|
||||
"start": "NODE_ENV=production node build/index.js",
|
||||
"test": "mocha --watch src",
|
||||
"watch": "webpack --watch --mode development"
|
||||
},
|
||||
"dependencies": {
|
||||
"@latus/core": "^1.0.0",
|
||||
"@latus/db": "^1.0.0",
|
||||
"@latus/governor": "^1.0.0",
|
||||
"@latus/http": "^1.0.0",
|
||||
"@latus/react": "^1.0.0",
|
||||
"@latus/redis": "^1.0.0",
|
||||
"@latus/repl": "^1.0.0",
|
||||
"@latus/socket": "^1.0.0",
|
||||
"@latus/user": "^1.0.0",
|
||||
"classnames": "^2.2.6",
|
||||
"dotenv": "8.2.0",
|
||||
"react-hot-loader": "4.13.0",
|
||||
"react-router-dom": "^5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb-base": "^9.1.0",
|
||||
"@neutrinojs/clean": "^9.1.0",
|
||||
"@neutrinojs/mocha": "^9.1.0",
|
||||
"@neutrinojs/node": "^9.1.0",
|
||||
"babel-plugin-webpack-alias": "^2.1.2",
|
||||
"eslint": "^6",
|
||||
"eslint-import-resolver-webpack": "^0.12.1",
|
||||
"js-yaml": "3.14.0",
|
||||
"neutrino": "^9.1.0",
|
||||
"source-map-support": "0.5.19",
|
||||
"webpack": "^4",
|
||||
"webpack-cli": "^3"
|
||||
}
|
||||
}
|
3
app/postcss.config.js
Normal file
3
app/postcss.config.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
plugins: {},
|
||||
};
|
1
app/src/index.js
Normal file
1
app/src/index.js
Normal file
|
@ -0,0 +1 @@
|
|||
process.stdout.write('Your application is starting...\n');
|
119
app/src/react/components/about/index.jsx
Normal file
119
app/src/react/components/about/index.jsx
Normal file
|
@ -0,0 +1,119 @@
|
|||
import './index.scss';
|
||||
|
||||
import React from 'react';
|
||||
import {Link} from 'react-router-dom';
|
||||
|
||||
const About = () => (
|
||||
<div className="about">
|
||||
<h1 className="about__title">
|
||||
<span className="about__titleMessage">
|
||||
<span class="about__nowrap">Hi!</span> <span class="about__nowrap about__smile">^_^</span>
|
||||
{' '}
|
||||
<img
|
||||
alt="cha0s's icon"
|
||||
title="This is a photo-realistic portrait. I have telekinetic powers."
|
||||
className="about__avatar"
|
||||
src="http://i.imgur.com/Xf7KBRR.png"
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
<section className="about__explains">
|
||||
<h2>reddichat is a chat site for redditors</h2>
|
||||
<p>
|
||||
Chatting with people on reddit.com is
|
||||
{' '}
|
||||
<em>okay</em>
|
||||
, but it's kinda lame. I built this site for fun and because I thought it would be
|
||||
{' '}
|
||||
an interesting project. I recently brought it back from the dead after about 5 years.
|
||||
Spooooky.
|
||||
</p>
|
||||
<h2>
|
||||
Don't expect permanent logs
|
||||
{' '}
|
||||
<small>
|
||||
...that means you too, 3-letter bois
|
||||
</small>
|
||||
</h2>
|
||||
<p>
|
||||
I'm big on privacy and all that, so I'm not keeping any permanent logs of this
|
||||
chat. This may or may not be a good idea. I could go either way. I am inclined to suggest
|
||||
that only through the transient nature of existence can we truly appreciate its permanence.
|
||||
Or something.
|
||||
</p>
|
||||
<p>
|
||||
Chat and private messages last for
|
||||
{' '}
|
||||
<strong style={{color: 'cyan'}}>10</strong>
|
||||
{' '}
|
||||
minutes. Messages in /r/anonymous last for
|
||||
{' '}
|
||||
<strong style={{color: 'orange'}}>1</strong>
|
||||
{' '}
|
||||
minute.
|
||||
</p>
|
||||
<h2>Be excellent to each other</h2>
|
||||
<p>
|
||||
This service has one simple rule, which you agree to respect when using it:
|
||||
{' '}
|
||||
<a
|
||||
className="about__dont-be-a-dick"
|
||||
href="http://meta.wikimedia.org/wiki/Don%27t_be_a_dick#Fundamentals"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Don't be a dick
|
||||
</a>
|
||||
</p>
|
||||
<p>♡ Please and thank you! ♡</p>
|
||||
<p className="about__caveat">
|
||||
Small caveat: I do like the idea of having an unmoderated space.
|
||||
{' '}
|
||||
<Link to="/chat/r/anonymous">/r/anonymous</Link>
|
||||
{' '}
|
||||
is that space. If you think that anonymous people on the Internet saying
|
||||
stupid/offensive/ignorant/inflammatory things sucks, then I urge you to stay out. There be
|
||||
dragons. You have been warned. You can go yell at them in there about it if you
|
||||
like.<br /><strong>That's the point!</strong>
|
||||
</p>
|
||||
<br />
|
||||
<p className="about__caveat">
|
||||
Also keep in mind that <strong>I can always see your IP address</strong>,
|
||||
and <strong>if you do anything actually illegal, I won't cover for you.</strong>
|
||||
</p>
|
||||
<h2>Still here?</h2>
|
||||
<p>Let me tell you some facts about this site.</p>
|
||||
<p>
|
||||
It's written in JavaScript on top of a handcrafted application framework I am
|
||||
calling <strong>latus</strong> for now. It's pretty neat, if you're a nerd.
|
||||
</p>
|
||||
<p>
|
||||
The frontend uses React/Redux and the backend uses Node.js/Express/Passport/Redis/MySQL.
|
||||
Real-time communication is accomplished with my own packet netcode built on top of
|
||||
socket.io.
|
||||
</p>
|
||||
<p>
|
||||
Also notable is that this site was created with
|
||||
{' '}
|
||||
<strong>love</strong>
|
||||
, as are all my creations. I hope that you have a great time using it. :)
|
||||
</p>
|
||||
<h2>Feeling charitable?</h2>
|
||||
<div className="about__crypto">
|
||||
<span className="coin-type btc" title="Bitcoin" />
|
||||
<span>
|
||||
If you'd like to contribute, send some bitcoin to
|
||||
{' '}
|
||||
<a
|
||||
href="bitcoin:3CrCpsrzxaFyXUuLuokjatAXxTq3skxCzh"
|
||||
>
|
||||
3CrCpsrzxaFyXUuLuokjatAXxTq3skxCzh
|
||||
</a>
|
||||
.
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default About;
|
110
app/src/react/components/about/index.scss
Normal file
110
app/src/react/components/about/index.scss
Normal file
|
@ -0,0 +1,110 @@
|
|||
@import 'scss/breakpoints.scss';
|
||||
@import 'scss/colors.scss';
|
||||
|
||||
.about {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 2em;
|
||||
font-family: var(--thick-title-font-family);
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
strong {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.about h2 {
|
||||
color: #aaaaaa;
|
||||
margin: 1.5em 0 0.5em;
|
||||
small {
|
||||
display: block;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.about small {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
.about a {
|
||||
color: lighten($color-active, 20%);
|
||||
}
|
||||
|
||||
.about p {
|
||||
margin: auto;
|
||||
&:not(:first-child) {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
@include breakpoint(tablet) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.about__nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.about__explains {
|
||||
margin: auto;
|
||||
padding-bottom: 2em;
|
||||
@include breakpoint(desktop) {
|
||||
max-width: calc(100% - 10em);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.about__inner {
|
||||
padding: 1em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.about__avatar {
|
||||
// margin-left: 0.5em;
|
||||
max-height: 1em;
|
||||
}
|
||||
|
||||
.about__title {
|
||||
background-color: #171717;
|
||||
display: flex;
|
||||
font-family: var(--title-font-family);
|
||||
font-size: 2em;
|
||||
justify-content: space-around;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
@include breakpoint(tiny) {
|
||||
font-size: 2.5em;
|
||||
padding: 1em;
|
||||
}
|
||||
@include breakpoint(tablet) {
|
||||
font-size: 4em;
|
||||
padding: 1em;
|
||||
}
|
||||
@include breakpoint(desktop) {
|
||||
margin: auto;
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.about__smile {
|
||||
display: inline-block;
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
.about__titleMessage {
|
||||
// display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.about__dont-be-a-dick {
|
||||
display: flow-root;
|
||||
margin: 1em 0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.about__crypto {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.about__caveat {
|
||||
font-size: 0.7em;
|
||||
}
|
40
app/src/react/components/app/index.jsx
Normal file
40
app/src/react/components/app/index.jsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
import './index.scss';
|
||||
|
||||
import React from 'react';
|
||||
import {hot} from 'react-hot-loader';
|
||||
import {Route, Router, Switch} from 'react-router-dom';
|
||||
import {createBrowserHistory} from 'history';
|
||||
|
||||
import About from 'components/about';
|
||||
import Chat from 'components/chat';
|
||||
import Home from 'components/home';
|
||||
import Left from 'components/left';
|
||||
import Right from 'components/right';
|
||||
|
||||
const history = createBrowserHistory();
|
||||
|
||||
const App = () => (
|
||||
<div className="app">
|
||||
<Left />
|
||||
<Router history={history}>
|
||||
<Switch>
|
||||
<Route
|
||||
component={Home}
|
||||
exact
|
||||
path="/"
|
||||
/>
|
||||
<Route
|
||||
component={About}
|
||||
path="/about"
|
||||
/>
|
||||
<Route
|
||||
component={Chat}
|
||||
path="/chat"
|
||||
/>
|
||||
</Switch>
|
||||
</Router>
|
||||
<Right />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default hot(module)(App);
|
35
app/src/react/components/app/index.scss
Normal file
35
app/src/react/components/app/index.scss
Normal file
|
@ -0,0 +1,35 @@
|
|||
@import 'scss/colors.scss';
|
||||
|
||||
.app {
|
||||
background-image: url('~images/transpaper.png');
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.panes {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
&.horizontal > .pane {
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
&.vertical > .pane {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.unread {
|
||||
background-color: $color-unread;
|
||||
border-radius: 10px;
|
||||
display: inline-block;
|
||||
font-family: var(--message-font-family);
|
||||
font-size: 0.6em;
|
||||
font-weight: bold;
|
||||
margin-right: 0.6em;
|
||||
padding: 0.4em;
|
||||
text-align: center;
|
||||
}
|
1
app/src/react/components/chat/index.jsx
Normal file
1
app/src/react/components/chat/index.jsx
Normal file
|
@ -0,0 +1 @@
|
|||
export default () => null;
|
41
app/src/react/components/home/index.jsx
Normal file
41
app/src/react/components/home/index.jsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
import './index.scss';
|
||||
|
||||
import React, {useEffect} from 'react';
|
||||
import {Link} from 'react-router-dom';
|
||||
|
||||
export default function Home() {
|
||||
useEffect(() => {
|
||||
window.document.title = 'reddichat';
|
||||
});
|
||||
return (
|
||||
<div className="home">
|
||||
<div className="home__inner">
|
||||
<h1 className="home__title">Reddi? Chat!</h1>
|
||||
<div className="home__bar">
|
||||
<div className="home__login-wrapper">
|
||||
<a className="home__login button" href="/auth/reddit">Touch to start</a>
|
||||
</div>
|
||||
<p className="home__instructions">
|
||||
You will be sent to reddit to log in.
|
||||
reddit will simply confirm your reddichat login and send you back here.
|
||||
Then you can chat!
|
||||
</p>
|
||||
<p className="home__anonymous">
|
||||
If you are exceptionally brave (or particularly toxic), you may choose to
|
||||
{' '}
|
||||
<Link to="/chat/r/anonymous">chat anonymously</Link>
|
||||
.
|
||||
</p>
|
||||
<p className="home__about">
|
||||
If you'd like to read a bit about the site, see the
|
||||
{' '}
|
||||
<Link to="/about">about page</Link>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Home.propTypes = {};
|
87
app/src/react/components/home/index.scss
Normal file
87
app/src/react/components/home/index.scss
Normal file
|
@ -0,0 +1,87 @@
|
|||
@import 'scss/breakpoints.scss';
|
||||
@import 'scss/colors.scss';
|
||||
|
||||
.home {
|
||||
margin: auto;
|
||||
max-width: map-get($breakpoints, desktop);
|
||||
}
|
||||
|
||||
.home__inner {
|
||||
padding: 1em;
|
||||
@include breakpoint(desktop) {
|
||||
padding: 3em 1em 1em;
|
||||
}
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.home__title {
|
||||
background-color: #171717;
|
||||
font-family: var(--title-font-family);
|
||||
font-size: 2em;
|
||||
padding: 1em;
|
||||
text-align: center;
|
||||
@include breakpoint(tiny) {
|
||||
font-size: 2.5em;
|
||||
padding: 2em;
|
||||
}
|
||||
@include breakpoint(tablet) {
|
||||
font-size: 4em;
|
||||
padding: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.home__bar {
|
||||
padding: 2em 0;
|
||||
}
|
||||
|
||||
.home__login-wrapper {
|
||||
padding-top: 1em;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
@include breakpoint(desktop) {
|
||||
padding-top: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.home__login {
|
||||
background-color: $color-active;
|
||||
display: inline-block;
|
||||
font-family: var(--thick-title-font-family);
|
||||
font-size: 2em;
|
||||
padding: 1em;
|
||||
text-decoration: none;
|
||||
transition: background-color 0.2s;
|
||||
&:hover {
|
||||
background-color: lighten($color-active, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.home__instructions {
|
||||
font-family: var(--message-font-family);
|
||||
font-size: 1.5em;
|
||||
line-height: 1.5em;
|
||||
padding: 2em 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
@include breakpoint(desktop) {
|
||||
font-size: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.home__anonymous {
|
||||
line-height: 1.5em;
|
||||
text-align: center;
|
||||
a {
|
||||
color: lighten($color-active, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
.home__about {
|
||||
font-size: 0.8em;
|
||||
line-height: 1em;
|
||||
margin-top: 2em;
|
||||
text-align: center;
|
||||
a {
|
||||
color: lighten($color-active, 20%);
|
||||
}
|
||||
}
|
65
app/src/react/components/left/index.jsx
Normal file
65
app/src/react/components/left/index.jsx
Normal file
|
@ -0,0 +1,65 @@
|
|||
import './index.scss';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
// import {useDispatch, useSelector} from 'react-redux';
|
||||
|
||||
// import {
|
||||
// leftActiveIndexSelector,
|
||||
// leftIsOpenSelector,
|
||||
// setLeftActiveIndex,
|
||||
// } from '~/common/state/app';
|
||||
// import {
|
||||
// idSelector,
|
||||
// pendingFriendshipSelector,
|
||||
// unreadChannelSelector,
|
||||
// unreadUserSelector,
|
||||
// } from '~/common/state/user';
|
||||
|
||||
// import Bar from './bar';
|
||||
// import Branding from './branding';
|
||||
// import ChatLeftFriends from './chat--leftFriends';
|
||||
// import ChatLeftRooms from './chat--leftRooms';
|
||||
|
||||
export default function ChatLeft() {
|
||||
// const dispatch = useDispatch();
|
||||
// const leftActiveIndex = useSelector(leftActiveIndexSelector);
|
||||
// const active = useSelector(leftActiveIndexSelector);
|
||||
// const isOpen = useSelector(leftIsOpenSelector);
|
||||
// const id = useSelector(idSelector);
|
||||
// const pendingFriendship = useSelector(pendingFriendshipSelector)
|
||||
// .filter(({addeeId}) => addeeId === id).length;
|
||||
// const unreadChannel = useSelector(unreadChannelSelector);
|
||||
// const unreadUser = useSelector(unreadUserSelector);
|
||||
const showsAsOpen = true;
|
||||
// const leftButtons = [
|
||||
// {
|
||||
// count: unreadChannel,
|
||||
// icon: '💬',
|
||||
// label: 'Chat',
|
||||
// },
|
||||
// {
|
||||
// count: unreadUser + pendingFriendship,
|
||||
// icon: '😁',
|
||||
// label: 'Friends',
|
||||
// },
|
||||
// ];
|
||||
return (
|
||||
<div
|
||||
className={classnames('left', 'flexed', showsAsOpen ? 'open' : 'closed')}
|
||||
>
|
||||
{/* <Branding />
|
||||
<Bar
|
||||
active={leftActiveIndex}
|
||||
buttons={leftButtons}
|
||||
className="bar--left"
|
||||
isHorizontal
|
||||
onActive={(active) => dispatch(setLeftActiveIndex(active))}
|
||||
/>
|
||||
{0 === active && <ChatLeftRooms />}
|
||||
{1 === active && <ChatLeftFriends />} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ChatLeft.propTypes = {};
|
22
app/src/react/components/left/index.scss
Normal file
22
app/src/react/components/left/index.scss
Normal file
|
@ -0,0 +1,22 @@
|
|||
@import 'scss/breakpoints.scss';
|
||||
@import 'scss/colors.scss';
|
||||
|
||||
.left {
|
||||
background-color: #373737;
|
||||
flex-shrink: 0;
|
||||
height: 100%;
|
||||
transform: translateX(-100%);
|
||||
transition: width 0.2s;
|
||||
width: 25em;
|
||||
@include breakpoint(desktop) {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.left .bar__buttonItem:last-child {
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
.bar--left {
|
||||
display: inline-block;
|
||||
}
|
57
app/src/react/components/right/index.jsx
Normal file
57
app/src/react/components/right/index.jsx
Normal file
|
@ -0,0 +1,57 @@
|
|||
import './index.scss';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
// import {useDispatch, useSelector} from 'react-redux';
|
||||
import {Link} from 'react-router-dom';
|
||||
|
||||
// import {
|
||||
// rightActiveIndexSelector,
|
||||
// rightIsOpenSelector,
|
||||
// setRightActiveIndex,
|
||||
// } from '~/common/state/app';
|
||||
// import {channelUsersSelector} from '~/common/state/chat';
|
||||
// import {
|
||||
// blockedSelector,
|
||||
// } from '~/common/state/user';
|
||||
|
||||
// import useChannel from '~/client/hooks/useChannel';
|
||||
|
||||
// import Bar from './bar';
|
||||
// import ChatRightBlocked from './chat--rightBlocked';
|
||||
// import ChatRightUsers from './chat--rightUsers';
|
||||
|
||||
export default function ChatRight() {
|
||||
// const dispatch = useDispatch();
|
||||
// const activeIndex = useSelector(rightActiveIndexSelector);
|
||||
// const channel = useChannel();
|
||||
// const blockedIds = useSelector(blockedSelector);
|
||||
// const channelUsers = useSelector((state) => channelUsersSelector(state, channel));
|
||||
// const isOpen = useSelector(rightIsOpenSelector);
|
||||
const showsAsOpen = true;
|
||||
// const rightButtons = []
|
||||
// .concat(channelUsers.length > 0 ? [{icon: '🙃', label: 'Present'}] : [])
|
||||
// .concat(blockedIds.length > 0 ? [{icon: '☢️', label: 'Blocked'}] : []);
|
||||
return (
|
||||
<div
|
||||
className={classnames('right', 'flexed', showsAsOpen ? 'open' : 'closed')}
|
||||
>
|
||||
{/* <Bar
|
||||
active={activeIndex}
|
||||
buttons={rightButtons}
|
||||
className="bar--right"
|
||||
isHorizontal
|
||||
onActive={(activeIndex) => dispatch(setRightActiveIndex(activeIndex))}
|
||||
/>
|
||||
<div className="right__links">
|
||||
<Link className="right__link" to="/about">About</Link>
|
||||
<span className="right__linksBullet">•</span>
|
||||
<Link className="right__link" to="/logout">Log out</Link>
|
||||
</div>
|
||||
{0 === activeIndex && channelUsers.length > 0 && <ChatRightUsers />}
|
||||
{1 === activeIndex && blockedIds.length > 0 && <ChatRightBlocked ids={blockedIds} />} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ChatRight.propTypes = {};
|
81
app/src/react/components/right/index.scss
Normal file
81
app/src/react/components/right/index.scss
Normal file
|
@ -0,0 +1,81 @@
|
|||
@import 'scss/breakpoints.scss';
|
||||
@import 'scss/colors.scss';
|
||||
|
||||
.right {
|
||||
background-color: #373737;
|
||||
flex-shrink: 0;
|
||||
right: 0;
|
||||
transform: translateX(100%);
|
||||
transition: 0.2s width;
|
||||
@include breakpoint(desktop) {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.right.open {
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.right__buttons {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
.right--closed & {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.right__buttonItem {
|
||||
padding: 0.5em;
|
||||
.right.closed & {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.right.open & {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.right__button {
|
||||
background-color: #2a2a2a;
|
||||
border: none;
|
||||
height: 3.5em;
|
||||
transition: 0.1s background-color;
|
||||
width: 3.5em;
|
||||
&:hover {
|
||||
background-color: #272727;
|
||||
}
|
||||
&.active {
|
||||
background-color: #555555;
|
||||
}
|
||||
}
|
||||
|
||||
.right__buttonIcon {
|
||||
display: flow-root;
|
||||
}
|
||||
|
||||
.right__buttonText {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
.right__links {
|
||||
background-color: #272727;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.right__linksBullet {
|
||||
color: #888;
|
||||
font-size: 0.5em;
|
||||
line-height: 2em;
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
.right__link {
|
||||
color: lighten($color-active, 20%);
|
||||
font-family: var(--thick-title-font-family);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
&:hover {
|
||||
color: lighten($color-active, 40%);
|
||||
}
|
||||
}
|
BIN
app/src/react/fonts/Lato-Light.eot
Normal file
BIN
app/src/react/fonts/Lato-Light.eot
Normal file
Binary file not shown.
BIN
app/src/react/fonts/Lato-Light.ttf
Normal file
BIN
app/src/react/fonts/Lato-Light.ttf
Normal file
Binary file not shown.
BIN
app/src/react/fonts/Lato-Light.woff
Normal file
BIN
app/src/react/fonts/Lato-Light.woff
Normal file
Binary file not shown.
BIN
app/src/react/fonts/Lato-Regular.eot
Normal file
BIN
app/src/react/fonts/Lato-Regular.eot
Normal file
Binary file not shown.
BIN
app/src/react/fonts/Lato-Regular.ttf
Normal file
BIN
app/src/react/fonts/Lato-Regular.ttf
Normal file
Binary file not shown.
BIN
app/src/react/fonts/Lato-Regular.woff
Normal file
BIN
app/src/react/fonts/Lato-Regular.woff
Normal file
Binary file not shown.
BIN
app/src/react/images/transpaper.png
Normal file
BIN
app/src/react/images/transpaper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 492 KiB |
9
app/src/react/index.jsx
Normal file
9
app/src/react/index.jsx
Normal file
|
@ -0,0 +1,9 @@
|
|||
import './index.scss';
|
||||
|
||||
import App from 'components/app';
|
||||
|
||||
export default {
|
||||
hooks: {
|
||||
'@latus/react/components': () => App,
|
||||
},
|
||||
};
|
278
app/src/react/index.scss
Normal file
278
app/src/react/index.scss
Normal file
|
@ -0,0 +1,278 @@
|
|||
@import 'scss/colors.scss';
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
em {
|
||||
font-style: italic;
|
||||
}
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
h4 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
h5 {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
h6 {
|
||||
font-size: 1.05em;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html {
|
||||
background-color: #212121;
|
||||
color: #FFFFFF;
|
||||
--message-font-family: verdana, arial, helvetica, sans-serif;
|
||||
--title-font-family: LatoLight, Ubuntu, "Droid Sans", sans-serif;
|
||||
--thick-title-font-family: LatoRegular, Ubuntu, "Droid Sans", sans-serif;
|
||||
}
|
||||
body {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #777 #333;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: #333;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #777;
|
||||
border-radius: 20px;
|
||||
border: 3px solid #333;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
label {
|
||||
background-color: rgba(255, 255, 255, 0.025);
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
font-family: var(--thick-title-font-family);
|
||||
font-size: 1em;
|
||||
min-height: 3em;
|
||||
padding: 0.5em 0.5em 0.5em 1em;
|
||||
user-select: none;
|
||||
@media(min-width: 20em) {
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
label:nth-of-type(2n+1) {
|
||||
background-color: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
|
||||
[contenteditable] {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
input {
|
||||
background: #333;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #ffffff;
|
||||
font-size: 0.75em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
background-color: #151515;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
display: inline-block;
|
||||
margin: 0 0 1em 0;
|
||||
padding: 0.5em;
|
||||
position: relative;
|
||||
top: -0.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button, .button {
|
||||
background: #222222;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #ffffff;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
button, .button, input[type="checkbox"], input[type="checkbox"] + label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
background: #222222;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #ffffff;
|
||||
cursor: pointer;
|
||||
font-size: 0.75em;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
*:focus {
|
||||
box-shadow: 0 0 2px 0 $color-active;
|
||||
outline: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.react-tabs {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.react-tabs__tab-list {
|
||||
background-color: #272727;
|
||||
font-family: var(--title-font-family);
|
||||
font-size: 0.9em;
|
||||
overflow-x: hidden;
|
||||
scrollbar-width: thin;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #2e1d1d;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: #777;
|
||||
border-radius: 0;
|
||||
border-width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.react-tabs__tab {
|
||||
background-color: #2d2d2d;
|
||||
color: #aaaaaa;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 3em;
|
||||
&:not(:last-of-type) {
|
||||
border-right: 1px solid #282828;
|
||||
}
|
||||
&:hover {
|
||||
color: #ddd;
|
||||
}
|
||||
.wrapper {
|
||||
align-content: space-between;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 0 0.5em;
|
||||
justify-content: space-evenly;
|
||||
.text {
|
||||
height: 1.25em;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
padding: 0 0.25em 0 0.5em;
|
||||
}
|
||||
.close {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: #999999;
|
||||
padding: 0.25em;
|
||||
visibility: hidden;
|
||||
&:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
&:hover .close {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.react-tabs__tab--selected[class] {
|
||||
background-color: #1e1e1e;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.react-tabs__tab-panel {
|
||||
display: none;
|
||||
overflow-y: auto;
|
||||
height: calc(100% - 2.7em);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.react-tabs__tab-panel--selected {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: $color-muted;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'LatoLight';
|
||||
src: url('./fonts/Lato-Light.eot');
|
||||
src: url('./fonts/Lato-Light.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('./fonts/Lato-Light.woff') format('woff'), /* Modern Browsers */ url('./fonts/Lato-Light.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'LatoRegular';
|
||||
src: url('./fonts/Lato-Regular.eot');
|
||||
src: url('./fonts/Lato-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('./fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */ url('./fonts/Lato-Regular.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
31
app/src/react/scss/breakpoints.scss
Normal file
31
app/src/react/scss/breakpoints.scss
Normal file
|
@ -0,0 +1,31 @@
|
|||
$breakpoints: (
|
||||
tiny: 320px,
|
||||
tablet: 720px,
|
||||
desktop: 1280px,
|
||||
hd: 1920px,
|
||||
uhd: 3840px,
|
||||
);
|
||||
|
||||
@mixin breakpoint($breakpoint, $min-max: 'min-width') {
|
||||
$output: false;
|
||||
@if (type-of($breakpoint) == number) {
|
||||
$output: $breakpoint;
|
||||
}
|
||||
@else {
|
||||
@if $min-max == 'max-width' {
|
||||
$output: #{map-get($breakpoints, $breakpoint) - 1px };
|
||||
}
|
||||
@else {
|
||||
$output: #{map-get($breakpoints, $breakpoint)};
|
||||
}
|
||||
}
|
||||
@if $breakpoint == default {
|
||||
@content;
|
||||
}
|
||||
@else {
|
||||
@media ($min-max: #{$output}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
app/src/react/scss/colors.scss
Normal file
4
app/src/react/scss/colors.scss
Normal file
|
@ -0,0 +1,4 @@
|
|||
$color-active: rgb(0, 99, 112);
|
||||
$color-muted: #bbbbbb;
|
||||
$color-owner: #d65130;
|
||||
$color-unread: rgb(180, 0, 0);
|
35
app/webpack.config.js
Normal file
35
app/webpack.config.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Whilst the configuration object can be modified here, the recommended way of making
|
||||
// changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead.
|
||||
// Neutrino's inspect feature can be used to view/export the generated configuration.
|
||||
const {join} = require('path');
|
||||
|
||||
const {readConfig, Latus} = require('@latus/core');
|
||||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const config = readConfig();
|
||||
const paths = Object.entries(config).map(([plugin]) => {
|
||||
try {
|
||||
require.resolve(plugin);
|
||||
return plugin;
|
||||
}
|
||||
catch (error) {
|
||||
return join(process.cwd(), plugin);
|
||||
}
|
||||
});
|
||||
const latus = new Latus({
|
||||
config,
|
||||
modules: paths.map((path) => require(path)),
|
||||
});
|
||||
const configs = {
|
||||
app: require('./.neutrinorc'),
|
||||
};
|
||||
latus.invokeFlat('@latus/core/build', configs);
|
||||
const webpackConfigs = Object.values(configs).map((config) => neutrino(config).webpack());
|
||||
resolve(webpackConfigs);
|
||||
}
|
||||
catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
8843
app/yarn.lock
Normal file
8843
app/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
22
config/.eslint.defaults.js
Normal file
22
config/.eslint.defaults.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const config = {
|
||||
globals: {
|
||||
process: true,
|
||||
window: true,
|
||||
},
|
||||
ignorePatterns: [
|
||||
'/*',
|
||||
'!/src',
|
||||
],
|
||||
rules: {
|
||||
'babel/object-curly-spacing': 'off',
|
||||
'brace-style': ['error', 'stroustrup'],
|
||||
'no-bitwise': ['error', {int32Hint: true}],
|
||||
'no-plusplus': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'padded-blocks': ['error', {classes: 'always'}],
|
||||
yoda: 'off',
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
3
config/.eslintrc.js
Normal file
3
config/.eslintrc.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)()).eslintrc();
|
5
config/.mocharc.js
Normal file
5
config/.mocharc.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const neutrino = require('neutrino');
|
||||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'test';
|
||||
|
||||
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)()).mocha();
|
34
config/.neutrinorc.js
Normal file
34
config/.neutrinorc.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
const airbnbBase = require('@neutrinojs/airbnb-base');
|
||||
const library = require('@neutrinojs/library');
|
||||
const mocha = require('@neutrinojs/mocha');
|
||||
|
||||
module.exports = () => ({
|
||||
options: {},
|
||||
use: [
|
||||
(neutrino) => {
|
||||
neutrino.options.output = '.';
|
||||
},
|
||||
airbnbBase({
|
||||
eslint: {
|
||||
cache: false,
|
||||
baseConfig: require(`${__dirname}/.eslint.defaults`),
|
||||
},
|
||||
}),
|
||||
(neutrino) => {
|
||||
const {name} = neutrino.options.packageJson;
|
||||
library({
|
||||
clean: false,
|
||||
name,
|
||||
target: 'node',
|
||||
})(neutrino);
|
||||
},
|
||||
(neutrino) => {
|
||||
const options = neutrino.config.module
|
||||
.rule('compile')
|
||||
.use('babel')
|
||||
.get('options');
|
||||
options.presets[0][1].targets = {esmodules: true};
|
||||
},
|
||||
mocha(),
|
||||
],
|
||||
});
|
3
config/package/.gitignore
vendored
Normal file
3
config/package/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/*.js
|
||||
/*.js.map
|
||||
!/webpack.config.js
|
36
config/package/package.json
Normal file
36
config/package/package.json
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "package",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "cha0s",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "NODE_PATH=./node_modules webpack --mode production",
|
||||
"clean": "rm -f yarn.lock && yarn",
|
||||
"dev": "NODE_PATH=./node_modules webpack --mode development",
|
||||
"forcepub": "npm unpublish --force $(node -e 'process.stdout.write(require(`./package.json`).name)') && npm publish",
|
||||
"lint": "NODE_PATH=./node_modules eslint --format codeframe --ext mjs,js .",
|
||||
"test": "NODE_PATH=./node_modules mocha --config ../../config/.mocharc.js",
|
||||
"watch": "NODE_PATH=./node_modules webpack --watch --mode development"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.js.map"
|
||||
],
|
||||
"dependencies": {
|
||||
"debug": "4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb-base": "^9.4.0",
|
||||
"@neutrinojs/copy": "9.4.0",
|
||||
"@neutrinojs/library": "^9.4.0",
|
||||
"@neutrinojs/mocha": "^9.4.0",
|
||||
"chai": "4.2.0",
|
||||
"eslint": "^7",
|
||||
"eslint-import-resolver-webpack": "0.13.0",
|
||||
"mocha": "^8",
|
||||
"neutrino": "^9.4.0",
|
||||
"webpack": "^4",
|
||||
"webpack-cli": "^3"
|
||||
}
|
||||
}
|
0
config/package/src/index.js
Normal file
0
config/package/src/index.js
Normal file
6
config/package/webpack.config.js
Normal file
6
config/package/webpack.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Whilst the configuration object can be modified here, the recommended way of making
|
||||
// changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead.
|
||||
// Neutrino's inspect feature can be used to view/export the generated configuration.
|
||||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();
|
39
config/split-config.js
Normal file
39
config/split-config.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
const library = require('@neutrinojs/library');
|
||||
|
||||
const config = require('./.neutrinorc');
|
||||
|
||||
module.exports = ({name, files}, clientMains) => {
|
||||
const mains = files
|
||||
.filter((file) => file.match(/\.js$/))
|
||||
.map((file) => file.slice(0, -3))
|
||||
.reduce((r, file) => ({...r, [file]: file}), {});
|
||||
|
||||
if (clientMains.length > 0) {
|
||||
const serverMains = Object
|
||||
.entries(mains)
|
||||
.filter(([key]) => -1 === clientMains.indexOf(key))
|
||||
.reduce((r, [k, v]) => ({...r, [k]: v}), {});
|
||||
const serverConfig = config();
|
||||
serverConfig.options.mains = serverMains;
|
||||
const clientConfig = config();
|
||||
clientConfig.options.mains = clientMains.reduce((r, file) => ({...r, [file]: file}), {});
|
||||
clientConfig.use[2] = (neutrino) => {
|
||||
library({
|
||||
clean: false,
|
||||
name,
|
||||
target: 'web',
|
||||
})(neutrino);
|
||||
};
|
||||
clientConfig.use.push((neutrino) => {
|
||||
neutrino.config.node.set('Buffer', true);
|
||||
});
|
||||
return [serverConfig, clientConfig];
|
||||
}
|
||||
else {
|
||||
const serverConfig = config();
|
||||
serverConfig.options = {
|
||||
mains,
|
||||
};
|
||||
return [serverConfig];
|
||||
}
|
||||
};
|
8
config/webpack.config.js
Normal file
8
config/webpack.config.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Whilst the configuration object can be modified here, the recommended way of making
|
||||
// changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead.
|
||||
// Neutrino's inspect feature can be used to view/export the generated configuration.
|
||||
const neutrino = require('neutrino');
|
||||
|
||||
const configOfConfigs = require(`${__dirname}/.neutrinorc`);
|
||||
const configs = Array.isArray(configOfConfigs) ? configOfConfigs : [configOfConfigs];
|
||||
module.exports = configs.map((config) => neutrino(config).webpack());
|
6
lerna.json
Normal file
6
lerna.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "1.0.0"
|
||||
}
|
25
package.json
Normal file
25
package.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "@reddichat/monorepo",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "lerna run build",
|
||||
"clean": "lerna run clean",
|
||||
"forcedev": "lerna run dev && lerna run forcepub",
|
||||
"lint": "lerna run lint",
|
||||
"test": "lerna run test",
|
||||
"watch": "lerna run watch --parallel"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb-base": "^9.4.0",
|
||||
"@neutrinojs/library": "^9.4.0",
|
||||
"@neutrinojs/mocha": "^9.4.0",
|
||||
"chai": "4.2.0",
|
||||
"eslint": "^7",
|
||||
"eslint-import-resolver-webpack": "0.13.0",
|
||||
"lerna": "^3.22.1",
|
||||
"mocha": "^8",
|
||||
"neutrino": "^9.4.0",
|
||||
"webpack": "^4",
|
||||
"webpack-cli": "^3"
|
||||
}
|
||||
}
|
3
packages/chat/.gitignore
vendored
Normal file
3
packages/chat/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/*.js
|
||||
/*.js.map
|
||||
!/webpack.config.js
|
38
packages/chat/package.json
Normal file
38
packages/chat/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "@reddichat/chat",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "cha0s",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "NODE_PATH=./node_modules webpack --mode production",
|
||||
"clean": "rm -f yarn.lock && yarn",
|
||||
"dev": "NODE_PATH=./node_modules webpack --mode development",
|
||||
"forcepub": "npm unpublish --force $(node -e 'process.stdout.write(require(`./package.json`).name)') && npm publish",
|
||||
"lint": "NODE_PATH=./node_modules eslint --format codeframe --ext mjs,js .",
|
||||
"test": "NODE_PATH=./node_modules mocha --config ../../config/.mocharc.js",
|
||||
"watch": "NODE_PATH=./node_modules webpack --watch --mode development"
|
||||
},
|
||||
"files": [
|
||||
"client.js",
|
||||
"client.js.map",
|
||||
"index.js",
|
||||
"index.js.map"
|
||||
],
|
||||
"dependencies": {
|
||||
"debug": "4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb-base": "^9.4.0",
|
||||
"@neutrinojs/copy": "9.4.0",
|
||||
"@neutrinojs/library": "^9.4.0",
|
||||
"@neutrinojs/mocha": "^9.4.0",
|
||||
"chai": "4.2.0",
|
||||
"eslint": "^7",
|
||||
"eslint-import-resolver-webpack": "0.13.0",
|
||||
"mocha": "^8",
|
||||
"neutrino": "^9.4.0",
|
||||
"webpack": "^4",
|
||||
"webpack-cli": "^3"
|
||||
}
|
||||
}
|
0
packages/chat/src/client/index.js
Normal file
0
packages/chat/src/client/index.js
Normal file
0
packages/chat/src/index.js
Normal file
0
packages/chat/src/index.js
Normal file
6
packages/chat/webpack.config.js
Normal file
6
packages/chat/webpack.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Whilst the configuration object can be modified here, the recommended way of making
|
||||
// changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead.
|
||||
// Neutrino's inspect feature can be used to view/export the generated configuration.
|
||||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();
|
3
packages/fun/.gitignore
vendored
Normal file
3
packages/fun/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/*.js
|
||||
/*.js.map
|
||||
!/webpack.config.js
|
38
packages/fun/package.json
Normal file
38
packages/fun/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "@reddichat/fun",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "cha0s",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "NODE_PATH=./node_modules webpack --mode production",
|
||||
"clean": "rm -f yarn.lock && yarn",
|
||||
"dev": "NODE_PATH=./node_modules webpack --mode development",
|
||||
"forcepub": "npm unpublish --force $(node -e 'process.stdout.write(require(`./package.json`).name)') && npm publish",
|
||||
"lint": "NODE_PATH=./node_modules eslint --format codeframe --ext mjs,js .",
|
||||
"test": "NODE_PATH=./node_modules mocha --config ../../config/.mocharc.js",
|
||||
"watch": "NODE_PATH=./node_modules webpack --watch --mode development"
|
||||
},
|
||||
"files": [
|
||||
"client.js",
|
||||
"client.js.map",
|
||||
"index.js",
|
||||
"index.js.map"
|
||||
],
|
||||
"dependencies": {
|
||||
"debug": "4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb-base": "^9.4.0",
|
||||
"@neutrinojs/copy": "9.4.0",
|
||||
"@neutrinojs/library": "^9.4.0",
|
||||
"@neutrinojs/mocha": "^9.4.0",
|
||||
"chai": "4.2.0",
|
||||
"eslint": "^7",
|
||||
"eslint-import-resolver-webpack": "0.13.0",
|
||||
"mocha": "^8",
|
||||
"neutrino": "^9.4.0",
|
||||
"webpack": "^4",
|
||||
"webpack-cli": "^3"
|
||||
}
|
||||
}
|
0
packages/fun/src/client/index.js
Normal file
0
packages/fun/src/client/index.js
Normal file
0
packages/fun/src/index.js
Normal file
0
packages/fun/src/index.js
Normal file
6
packages/fun/webpack.config.js
Normal file
6
packages/fun/webpack.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Whilst the configuration object can be modified here, the recommended way of making
|
||||
// changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead.
|
||||
// Neutrino's inspect feature can be used to view/export the generated configuration.
|
||||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();
|
3
packages/user/.gitignore
vendored
Normal file
3
packages/user/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/*.js
|
||||
/*.js.map
|
||||
!/webpack.config.js
|
38
packages/user/package.json
Normal file
38
packages/user/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "@reddichat/user",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "cha0s",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "NODE_PATH=./node_modules webpack --mode production",
|
||||
"clean": "rm -f yarn.lock && yarn",
|
||||
"dev": "NODE_PATH=./node_modules webpack --mode development",
|
||||
"forcepub": "npm unpublish --force $(node -e 'process.stdout.write(require(`./package.json`).name)') && npm publish",
|
||||
"lint": "NODE_PATH=./node_modules eslint --format codeframe --ext mjs,js .",
|
||||
"test": "NODE_PATH=./node_modules mocha --config ../../config/.mocharc.js",
|
||||
"watch": "NODE_PATH=./node_modules webpack --watch --mode development"
|
||||
},
|
||||
"files": [
|
||||
"client.js",
|
||||
"client.js.map",
|
||||
"index.js",
|
||||
"index.js.map"
|
||||
],
|
||||
"dependencies": {
|
||||
"debug": "4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb-base": "^9.4.0",
|
||||
"@neutrinojs/copy": "9.4.0",
|
||||
"@neutrinojs/library": "^9.4.0",
|
||||
"@neutrinojs/mocha": "^9.4.0",
|
||||
"chai": "4.2.0",
|
||||
"eslint": "^7",
|
||||
"eslint-import-resolver-webpack": "0.13.0",
|
||||
"mocha": "^8",
|
||||
"neutrino": "^9.4.0",
|
||||
"webpack": "^4",
|
||||
"webpack-cli": "^3"
|
||||
}
|
||||
}
|
0
packages/user/src/client/index.js
Normal file
0
packages/user/src/client/index.js
Normal file
0
packages/user/src/index.js
Normal file
0
packages/user/src/index.js
Normal file
6
packages/user/webpack.config.js
Normal file
6
packages/user/webpack.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Whilst the configuration object can be modified here, the recommended way of making
|
||||
// changes is via the presets' options or Neutrino's API in `.neutrinorc.js` instead.
|
||||
// Neutrino's inspect feature can be used to view/export the generated configuration.
|
||||
const neutrino = require('neutrino');
|
||||
|
||||
module.exports = neutrino(require(`${__dirname}/.neutrinorc`)).webpack();
|
Loading…
Reference in New Issue
Block a user