285 |
288 |
292 | { this.props.postData.account.developer.nick }
293 |
294 | { title ?
295 |
298 | { title }
299 |
300 | : ''
301 | }
302 |
303 | { postedString }
304 | { topicLinkNode }
305 |
306 |
{
314 | this.body = node;
315 | } }
316 | />
317 |
318 |
345 |
346 | );
347 | }
348 | }
349 |
350 | Post.propTypes = {
351 | postData: PropTypes.shape( {
352 | account: PropTypes.shape( {
353 | developer: PropTypes.shape( {
354 | group: PropTypes.string,
355 | name: PropTypes.string,
356 | nick: PropTypes.string,
357 | role: PropTypes.string,
358 | } ),
359 | identifier: PropTypes.string,
360 | service: PropTypes.string,
361 | } ),
362 | content: PropTypes.string,
363 | id: PropTypes.string,
364 | section: PropTypes.string,
365 | timestamp: PropTypes.number,
366 | topic: PropTypes.string,
367 | topicUrl: PropTypes.string,
368 | url: PropTypes.string,
369 | urlHash: PropTypes.string,
370 | } ).isRequired,
371 | postIndex: PropTypes.number,
372 | };
373 |
374 | export default Post;
375 |
--------------------------------------------------------------------------------
/app/components/PostList.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import Post from './Post.jsx';
5 |
6 | class PostList extends React.Component {
7 | render () {
8 | let postNodes = [];
9 |
10 | postNodes = this.props.posts.map( ( communityPost, index ) => {
11 | return (
12 |
17 | );
18 | } );
19 |
20 | return (
21 |
22 | { postNodes }
23 |
24 | );
25 | }
26 | }
27 |
28 | PostList.propTypes = {
29 | // eslint-disable-next-line react/forbid-prop-types
30 | posts: PropTypes.array.isRequired,
31 | };
32 |
33 | export default PostList;
34 |
--------------------------------------------------------------------------------
/app/components/Root.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Provider } from 'react-redux';
3 |
4 | import configureStore from '../store';
5 | import App from './App.jsx';
6 |
7 | const store = configureStore();
8 |
9 | window.reduxStore = store;
10 |
11 | class Root extends React.Component {
12 | constructor () {
13 | super();
14 |
15 | this.state = {
16 | key: Date.now(),
17 | };
18 | }
19 |
20 | componentDidMount(){
21 | window.addEventListener( 'gamechange', () => {
22 | this.setState( {
23 | key: Date.now(),
24 | } );
25 | } );
26 | }
27 |
28 | render () {
29 | console.log( 'got Root re-render' );
30 | return (
31 |
34 |
37 |
38 | );
39 | }
40 | }
41 |
42 | export default Root;
43 |
--------------------------------------------------------------------------------
/app/components/Search.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const styles = {
5 | clearer: {
6 | height: '15px',
7 | pointerEvents: 'auto',
8 | position: 'absolute',
9 | right: '6px',
10 | top: '6px',
11 | width: '15px',
12 | zIndex: 1,
13 | },
14 | };
15 |
16 | class Search extends React.Component {
17 | constructor ( props ) {
18 | super( props );
19 |
20 | this.handleSubmit = this.handleSubmit.bind( this );
21 | this.handleClearClick = this.handleClearClick.bind( this );
22 | this.handleChange = this.handleChange.bind( this );
23 | }
24 |
25 | handleSubmit ( event ) {
26 | event.preventDefault();
27 | }
28 |
29 | handleClearClick () {
30 | this.input.value = '';
31 | this.props.updateSearchTerm( '' );
32 | }
33 |
34 | handleChange ( event ) {
35 | this.props.updateSearchTerm( event.target.value );
36 | }
37 |
38 | render () {
39 | let clearerNode;
40 |
41 | if ( this.props.searchTerm.length > 0 ) {
42 | clearerNode = (
43 |
52 | );
53 | }
54 |
55 | return (
56 |
80 | );
81 | }
82 | }
83 |
84 | Search.displayName = 'Search';
85 |
86 | Search.propTypes = {
87 | searchTerm: PropTypes.string.isRequired,
88 | updateSearchTerm: PropTypes.func.isRequired,
89 | };
90 |
91 | export default Search;
92 |
--------------------------------------------------------------------------------
/app/components/ServiceCheckbox.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { connect } from 'react-redux';
4 |
5 | import {
6 | toggleService,
7 | } from '../actions';
8 |
9 | class ServiceCheckbox extends React.Component {
10 | getParsedServiceName () {
11 | return this.props.name
12 | .toLowerCase()
13 | .replace( /\s/gim, '-' )
14 | .replace( /[^a-z0-9-]/gim, '' );
15 | }
16 |
17 | render () {
18 | return (
19 |
22 |
36 |
37 | );
38 | }
39 | }
40 |
41 | const mapDispatchToProps = ( dispatch, ownProps ) => {
42 | return {
43 | handleCheckboxChange: () => {
44 | dispatch( toggleService( ownProps.name ) );
45 | },
46 | };
47 | };
48 |
49 | ServiceCheckbox.displayName = 'ServiceCheckbox';
50 |
51 | ServiceCheckbox.propTypes = {
52 | checked: PropTypes.bool.isRequired,
53 | handleCheckboxChange: PropTypes.func.isRequired,
54 | name: PropTypes.string.isRequired,
55 | label: PropTypes.string.isRequired,
56 | };
57 |
58 | export default connect(
59 | null,
60 | mapDispatchToProps
61 | )( ServiceCheckbox );
62 |
--------------------------------------------------------------------------------
/app/components/ServicesList.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import ServiceCheckbox from './ServiceCheckbox.jsx';
5 |
6 | class ServicesList extends React.Component {
7 | constructor ( props ) {
8 | super( props );
9 |
10 | this.handleFilterExpandClick = this.handleFilterExpandClick.bind( this );
11 |
12 | this.state = {
13 | showServices: true,
14 | };
15 | }
16 |
17 | componentWillMount () {
18 | if ( window.matchMedia && window.matchMedia( '( max-width: 450px )' ).matches ) {
19 | this.setState( {
20 | showServices: false,
21 | } );
22 | }
23 | }
24 |
25 | handleFilterExpandClick () {
26 | this.setState( {
27 | showServices: !this.state.showServices,
28 | } );
29 | }
30 |
31 | render () {
32 | let servicesClasses = 'services-wrapper';
33 |
34 | const serviceNodes = this.props.services.map( ( service ) => {
35 | return (
36 |
42 | );
43 | } );
44 |
45 | if ( serviceNodes.length < 1 ) {
46 | servicesClasses = `${ servicesClasses } hidden`;
47 | }
48 |
49 | if ( this.state.showServices ) {
50 | servicesClasses = `${ servicesClasses } show`;
51 | }
52 |
53 | return (
54 |
57 | { serviceNodes }
58 |
59 | );
60 | }
61 | }
62 |
63 | ServicesList.displayName = 'ServicesList';
64 |
65 | ServicesList.propTypes = {
66 | // eslint-disable-next-line
67 | services: PropTypes.array.isRequired,
68 | };
69 |
70 | export default ServicesList;
71 |
--------------------------------------------------------------------------------
/app/containers/FiltersContainer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { connect } from 'react-redux';
4 |
5 | import ServicesList from '../components/ServicesList.jsx';
6 | import Search from './Search.jsx';
7 | import GroupList from '../components/GroupList.jsx';
8 |
9 | class FiltersContainer extends React.Component {
10 | render () {
11 | return (
12 |
13 |
16 |
17 |
20 |
21 | );
22 | }
23 | }
24 |
25 | const mapStateToProps = function mapStateToProps ( state ) {
26 | const {
27 | groups,
28 | services,
29 | } = state;
30 |
31 | return {
32 | groups: groups.items || [],
33 | services: services.items || [],
34 | };
35 | };
36 |
37 | FiltersContainer.propTypes = {
38 | // eslint-disable-next-line react/forbid-prop-types
39 | groups: PropTypes.array.isRequired,
40 | // eslint-disable-next-line react/forbid-prop-types
41 | services: PropTypes.array.isRequired,
42 | };
43 |
44 | export default connect(
45 | mapStateToProps
46 | )( FiltersContainer );
47 |
--------------------------------------------------------------------------------
/app/containers/PostListContainer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { connect } from 'react-redux';
4 |
5 | import {
6 | fetchPostsIfNeeded,
7 | } from '../actions';
8 |
9 | import PostList from '../components/PostList.jsx';
10 | // import Loader from '../components/Loader.jsx';
11 | import NoPosts from '../components/NoPosts.jsx';
12 |
13 | class PostListContainer extends React.Component {
14 | componentDidMount () {
15 | this.props.getPosts();
16 | }
17 |
18 | render () {
19 | // if ( this.props.isFetching ) {
20 | // return (
21 | //
24 | // );
25 | // }
26 |
27 | if ( this.props.posts.length < 1 ) {
28 | return (
29 |
33 | );
34 | }
35 |
36 | return (
37 |
40 | );
41 | }
42 | }
43 |
44 | const mapStateToProps = function mapStateToProps ( state ) {
45 | const {
46 | posts,
47 | search,
48 | } = state;
49 |
50 | return {
51 | isFetching: posts.isFetching,
52 | posts: posts.items || [],
53 | searchString: search,
54 | };
55 | };
56 |
57 | const mapDispatchToProps = ( dispatch ) => {
58 | return {
59 | getPosts: () => {
60 | dispatch( fetchPostsIfNeeded() );
61 | },
62 | };
63 | };
64 |
65 | PostListContainer.propTypes = {
66 | isFetching: PropTypes.bool.isRequired,
67 | getPosts: PropTypes.func.isRequired,
68 | // eslint-disable-next-line react/forbid-prop-types
69 | posts: PropTypes.array.isRequired,
70 | };
71 |
72 | export default connect(
73 | mapStateToProps,
74 | mapDispatchToProps
75 | )( PostListContainer );
76 |
--------------------------------------------------------------------------------
/app/containers/Search.jsx:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 |
3 | import {
4 | search,
5 | } from '../actions';
6 |
7 | import Search from '../components/Search.jsx';
8 |
9 | const mapStateToProps = ( state ) => {
10 | return {
11 | searchTerm: state.search,
12 | };
13 | };
14 |
15 | const mapDispatchToProps = ( dispatch ) => {
16 | return {
17 | updateSearchTerm: ( searchTerm ) => {
18 | dispatch( search( searchTerm ) );
19 | },
20 | };
21 | };
22 |
23 | export default connect(
24 | mapStateToProps,
25 | mapDispatchToProps
26 | )( Search );
27 |
--------------------------------------------------------------------------------
/app/hooks/useStateWithLocalStorage.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 |
3 | const useStateWithLocalStorage = (localStorageKey, fallbackValue) => {
4 | let initialValue = localStorage.getItem(localStorageKey);
5 |
6 | if (initialValue === null) {
7 | initialValue = fallbackValue;
8 | } else {
9 | try {
10 | initialValue = JSON.parse(initialValue);
11 | } catch (jsonParseError) {
12 | // If we have something non-json in local storage, fall back to fallback value
13 | initialValue = fallbackValue;
14 | }
15 | }
16 |
17 | const [value, setValue] = useState(initialValue);
18 |
19 | useEffect(() => {
20 | localStorage.setItem(localStorageKey, JSON.stringify(value));
21 | }, [value, localStorageKey]);
22 |
23 | return [value, setValue];
24 | };
25 |
26 | export default useStateWithLocalStorage;
--------------------------------------------------------------------------------
/app/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createRoot } from 'react-dom/client';
3 |
4 | import Ad from './components/Ad.jsx';
5 | import Root from './components/Root.jsx';
6 |
7 | const ad1Container = document.getElementById( 'left-ad' );
8 | const ad1Root = createRoot(ad1Container);
9 | ad1Root.render(
);
12 |
13 | const ad2Container = document.getElementById( 'right-ad' );
14 | const ad2Root = createRoot(ad2Container);
15 | ad2Root.render(
);
18 |
19 | const pageContainer = document.getElementById( 'js-app' );
20 | const pageRoot = createRoot(pageContainer);
21 | pageRoot.render(
);
--------------------------------------------------------------------------------
/app/reducers.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import queryString from 'querystring';
3 | import cookie from 'react-cookie';
4 |
5 | import {
6 | RECEIVE_POSTS,
7 | REQUEST_POSTS,
8 | SET_SEARCH_TERM,
9 | TOGGLE_GROUP,
10 | TOGGLE_SERVICE,
11 | } from './actions';
12 |
13 | const groups = function groups ( state = {
14 | items: window.trackerData.groups,
15 | }, action ) {
16 | let updatedItems;
17 | const currentQuery = queryString.parse( location.search.substr( 1 ) );
18 |
19 | if ( typeof currentQuery[ 'groups[]' ] === 'string' ) {
20 | currentQuery[ 'groups[]' ] = [ currentQuery[ 'groups[]' ] ];
21 | }
22 |
23 | switch ( action.type ) {
24 | case TOGGLE_GROUP:
25 | if ( action.name === 'All' ) {
26 | updatedItems = state.items.map( ( group ) => {
27 | group.active = false;
28 |
29 | return group;
30 | } );
31 | } else {
32 | updatedItems = state.items.map( ( group ) => {
33 | if ( group.name === action.name ) {
34 | group.active = !group.active;
35 | }
36 |
37 | return group;
38 | } );
39 | }
40 |
41 | return Object.assign( {}, state, {
42 | items: updatedItems,
43 | } );
44 | default:
45 | if ( typeof currentQuery[ 'groups[]' ] !== 'undefined' ) {
46 | updatedItems = state.items.map( ( group ) => {
47 | if ( currentQuery[ 'groups[]' ].indexOf( group.name ) > -1 ) {
48 | group.active = true;
49 | } else {
50 | group.active = false;
51 | }
52 |
53 | return group;
54 | } );
55 |
56 | return Object.assign( {}, state, {
57 | items: updatedItems,
58 | } );
59 | }
60 |
61 | const active = state.items.filter( ( item ) => {
62 | return item.active;
63 | } );
64 |
65 | if ( active.length === state.items.length ) {
66 | state.items = state.items.map( ( item ) => {
67 | item.active = false;
68 |
69 | return item;
70 | } );
71 | }
72 |
73 | return state;
74 | }
75 | };
76 |
77 | const services = function services ( state = {
78 | items: window.trackerData.services,
79 | }, action ) {
80 | let updatedItems;
81 | const currentQuery = queryString.parse( location.search.substr( 1 ) );
82 |
83 | if ( typeof currentQuery[ 'services[]' ] === 'string' ) {
84 | currentQuery[ 'services[]' ] = [ currentQuery[ 'services[]' ] ];
85 | }
86 |
87 | switch ( action.type ) {
88 | case TOGGLE_SERVICE:
89 | updatedItems = state.items.map( ( service ) => {
90 | if ( service.name === action.name ) {
91 | service.active = !service.active;
92 | }
93 |
94 | return service;
95 | } );
96 |
97 | // Save an array of active services
98 | cookie.save( 'services',
99 | updatedItems
100 | .map( ( service ) => {
101 | if ( service.active ) {
102 | return service.name;
103 | }
104 |
105 | return false;
106 | } )
107 | .filter( ( service ) => {
108 | return service;
109 | } )
110 | , {
111 | path: '/',
112 | }
113 | );
114 |
115 | return Object.assign( {}, state, {
116 | items: updatedItems,
117 | } );
118 | default:
119 | // Check if we have a query of services
120 | if ( typeof currentQuery[ 'service[]' ] !== 'undefined' ) {
121 | updatedItems = state.items.map( ( service ) => {
122 | if ( currentQuery[ 'service[]' ].indexOf( service.name ) > -1 ) {
123 | service.active = true;
124 | } else {
125 | service.active = false;
126 | }
127 |
128 | return service;
129 | } );
130 |
131 | return Object.assign( {}, state, {
132 | items: updatedItems,
133 | } );
134 | }
135 |
136 | // Check if we have a cookie set for services
137 | if ( cookie.load( 'services' ) ) {
138 | const activeServices = cookie.load( 'services' );
139 |
140 | updatedItems = state.items.map( ( service ) => {
141 | if ( activeServices.indexOf( service.name ) > -1 ) {
142 | service.active = true;
143 | } else {
144 | service.active = false;
145 | }
146 |
147 | return service;
148 | } );
149 |
150 | return Object.assign( {}, state, {
151 | items: updatedItems,
152 | } );
153 | }
154 |
155 | return state;
156 | }
157 | };
158 |
159 | const search = function search ( state, action ) {
160 | const currentQuery = queryString.parse( location.search.substr( 1 ) );
161 |
162 | switch ( action.type ) {
163 | case SET_SEARCH_TERM:
164 | return action.term;
165 | default:
166 | if ( typeof currentQuery.search !== 'undefined' ) {
167 | return currentQuery.search;
168 | }
169 |
170 | return '';
171 | }
172 | };
173 |
174 | const posts = function posts ( state = {
175 | items: [],
176 | isFetching: true,
177 | }, action ) {
178 | switch ( action.type ) {
179 | case REQUEST_POSTS:
180 | return Object.assign( {}, state, {
181 | isFetching: true,
182 | } );
183 | case RECEIVE_POSTS:
184 | return Object.assign( {}, state, {
185 | items: action.posts,
186 | lastUpdated: action.receivedAt,
187 | isFetching: false,
188 | } );
189 | default:
190 | return state;
191 | }
192 | };
193 |
194 | const trackerApp = combineReducers( {
195 | groups,
196 | posts,
197 | search,
198 | services,
199 | } );
200 |
201 | export default trackerApp;
202 |
--------------------------------------------------------------------------------
/app/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware, compose } from 'redux';
2 | import thunkMiddleware from 'redux-thunk';
3 |
4 | import trackerApp from './reducers';
5 |
6 | export default function configureStore ( preloadedState ) {
7 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
8 | return createStore( trackerApp, preloadedState, composeEnhancers(
9 | applyMiddleware(
10 | thunkMiddleware
11 | )
12 | ) );
13 | }
14 |
--------------------------------------------------------------------------------
/dev/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 | !index.html
4 |
--------------------------------------------------------------------------------
/dev/assets/dev.css:
--------------------------------------------------------------------------------
1 | .dev-game-select-wrapper {
2 | background-color: rgba( 0, 0, 0, 0.6 );
3 | bottom: 3px;
4 | height: 30px;
5 | left: 3px;
6 | overflow: hidden;
7 | padding: 5px;
8 | position: fixed;
9 | }
10 |
11 | .dev-game-select-wrapper:hover {
12 | height: auto;
13 | }
14 |
15 | .dev-game-select {
16 | list-style: none;
17 | margin: 0;
18 | padding: 0;
19 | }
20 |
21 | .dev-game-select li a {
22 | display: block;
23 | text-transform: lowercase;
24 | padding: 0 3px;
25 | }
26 |
27 | .dev-game-select li a:hover {
28 | background-color: #111;
29 | }
--------------------------------------------------------------------------------
/dev/assets/dev.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | const getPathGame = function getPathGame() {
3 | const pathGame = window.location.pathname.replace( /\//g, '' );
4 |
5 | return pathGame;
6 | };
7 |
8 | if ( getPathGame() !== window.game ) {
9 | window.fetch( `https://api.developertracker.com/${ getPathGame() }/services` )
10 | .then( ( response ) => {
11 | return response.json();
12 | } )
13 | .then( ( services ) => {
14 | const currentState = window.reduxStore.getState();
15 | currentState.services.items = services.data.map( ( serviceName ) => {
16 | return {
17 | active: true,
18 | name: serviceName,
19 | label: serviceName,
20 | };
21 | } );
22 |
23 | return window.fetch( `https://api.developertracker.com/${ getPathGame() }/groups` );
24 | } )
25 | .then( ( response ) => {
26 | return response.json();
27 | } )
28 | .then( ( groups ) => {
29 | const currentState = window.reduxStore.getState();
30 | currentState.groups.items = groups.data.map( ( name ) => {
31 | return {
32 | active: true,
33 | name: name,
34 | };
35 | } );
36 |
37 | window.game = getPathGame();
38 | window.dispatchEvent( new Event( 'gamechange' ) );
39 | } )
40 | .catch( ( requestError ) => {
41 | throw requestError;
42 | } );
43 | }
44 |
45 | window.fetch( 'https://api.developertracker.com/games' )
46 | .then( ( response ) => {
47 | return response.json();
48 | } )
49 | .then( ( games ) => {
50 | let gameSelectString = '
';
51 | const sortedGames = games.data.sort( ( a, b ) => {
52 | return a.name.localeCompare( b.name );
53 | } );
54 |
55 | for ( let i = 0; i < sortedGames.length; i = i + 1 ) {
56 | gameSelectString = `${ gameSelectString }- ${ sortedGames[ i ].name }
`;
57 | }
58 |
59 | gameSelectString = `${ gameSelectString }
`;
60 |
61 | const wrapper = document.createElement( 'div' );
62 | wrapper.className = 'dev-game-select-wrapper';
63 | wrapper.innerHTML = gameSelectString;
64 |
65 | document.querySelectorAll( 'body' )[ 0 ].appendChild( wrapper );
66 | } )
67 | .catch( ( requestError ) => {
68 | throw requestError;
69 | } );
70 | })();
71 |
--------------------------------------------------------------------------------
/dev/assets/loader.svg:
--------------------------------------------------------------------------------
1 |
134 |
--------------------------------------------------------------------------------
/dev/assets/theme-dark.css:
--------------------------------------------------------------------------------
1 | *::-ms-clear {
2 | height: 0;
3 | width: 0; }
4 |
5 | body {
6 | font-size: 15px;
7 | line-height: 1.5; }
8 |
9 | blockquote {
10 | font-size: inherit; }
11 |
12 | br {
13 | content: ' ';
14 | display: block;
15 | margin: 15px auto; }
16 |
17 | h1 {
18 | text-align: center; }
19 |
20 | h1 a,
21 | h1 a:active,
22 | h1 a:hover {
23 | text-decoration: none; }
24 |
25 | .header-container {
26 | position: relative; }
27 |
28 | .header-link {
29 | position: absolute;
30 | right: 15px;
31 | top: 10px; }
32 |
33 | .header-link i {
34 | font-size: 1.8em;
35 | margin: 0; }
36 |
37 | .github-link {
38 | right: 45px; }
39 |
40 | .reddit-link {
41 | right: 75px; }
42 |
43 | .twitter-link {
44 | right: 105px; }
45 |
46 | .discord-link {
47 | right: 135px; }
48 |
49 | .patreon-link {
50 | right: 165px; }
51 |
52 | .panel {
53 | position: relative;
54 | word-wrap: break-word; }
55 |
56 | .panel-footer {
57 | position: relative;
58 | padding: 3px 15px;
59 | display: flex;
60 | justify-content: space-between;
61 | align-items: center; }
62 | .panel-footer .timed {
63 | display: flex;
64 | justify-content: space-between;
65 | align-items: center; }
66 | .panel-footer .timed .icon-a {
67 | font-size: 0; }
68 |
69 | .panel-body img {
70 | max-width: 100%; }
71 |
72 | .icon {
73 | height: 25px;
74 | width: 25px; }
75 |
76 | .clearer:hover {
77 | cursor: pointer; }
78 |
79 | .expandable {
80 | max-height: 500px;
81 | overflow: hidden; }
82 |
83 | .expander {
84 | bottom: 100%;
85 | left: 15px;
86 | padding-bottom: 20px;
87 | padding-top: 60px;
88 | position: absolute;
89 | right: 0; }
90 | .expander:hover {
91 | cursor: pointer;
92 | text-decoration: underline; }
93 |
94 | input[type="checkbox"],
95 | .checkbox input[type="checkbox"] {
96 | margin-bottom: 0;
97 | margin-right: 5px; }
98 |
99 | .filter-label {
100 | height: 23px;
101 | line-height: 23px;
102 | vertical-align: top; }
103 |
104 | .services-wrapper {
105 | text-align: center; }
106 |
107 | .service-checkbox,
108 | .service-checkbox + .service-checkbox {
109 | display: inline-block;
110 | margin: 5px 20px 5px 5px; }
111 |
112 | .service-checkbox label {
113 | height: 23px;
114 | width: 100%; }
115 |
116 | .groups-wrapper {
117 | margin: 0 auto 20px auto;
118 | text-align: center;
119 | width: 1040px; }
120 |
121 | .groups-wrapper input[type="checkbox"],
122 | .groups-wrapper .checkbox input[type="checkbox"] {
123 | height: 18px;
124 | width: 18px; }
125 |
126 | .groups-wrapper .filters-wrapper svg {
127 | transition: transform 0.3s ease; }
128 |
129 | .groups-wrapper.show .filters-wrapper svg {
130 | transform: rotate(180deg); }
131 |
132 | .groups-wrapper .checkbox {
133 | display: inline-block;
134 | font-size: 12px;
135 | margin: 5px;
136 | line-height: 15px; }
137 |
138 | .groups-wrapper .checkbox label {
139 | white-space: nowrap; }
140 |
141 | .group-label {
142 | background-position: center left;
143 | background-repeat: no-repeat;
144 | display: inline-block;
145 | height: 23px;
146 | line-height: 25px;
147 | overflow: hidden;
148 | text-align: left;
149 | text-overflow: ellipsis;
150 | white-space: nowrap; }
151 |
152 | .filters-wrapper {
153 | display: none; }
154 |
155 | .adsbygoogle {
156 | display: block; }
157 |
158 | .bb-spoiler-toggle + .bb-spoiler {
159 | display: none; }
160 |
161 | .bb-spoiler-toggle.active + .bb-spoiler {
162 | display: block; }
163 |
164 | .bb-spoiler {
165 | border: 1px dashed;
166 | margin: 10px 0;
167 | padding: 10px; }
168 |
169 | a.ipsAttachLink_image {
170 | display: flex;
171 | justify-content: center; }
172 |
173 | .services-wrapper label:hover {
174 | text-decoration: underline; }
175 |
176 | .has-feedback input[role=search] {
177 | padding: 0 15px; }
178 |
179 | @media screen and (max-width: 1800px) {
180 | .adsbygoogle {
181 | display: none; } }
182 |
183 | @media screen and (max-width: 1200px) {
184 | .groups-wrapper {
185 | text-align: center;
186 | width: auto; } }
187 |
188 | @media screen and (max-width: 660px) {
189 | .header-link {
190 | display: none; } }
191 |
192 | @media screen and (max-width: 480px) {
193 | h1 {
194 | font-size: 38px; }
195 | .services-wrapper {
196 | text-align: inherit; }
197 | .service-checkbox,
198 | .service-checkbox + .service-checkbox {
199 | margin: 0;
200 | text-align: left;
201 | width: 50%; }
202 | .service-checkbox:nth-child(odd) label {
203 | padding-right: 30px;
204 | padding-left: 0; }
205 | .service-checkbox:nth-child(odd) input[type="checkbox"] {
206 | float: right;
207 | margin-left: 10px;
208 | margin-right: -25px; }
209 | .service-checkbox:nth-child(even) input[type="checkbox"] {
210 | float: left; }
211 | .service-checkbox:nth-child(even) span {
212 | float: right; }
213 | .service-checkbox:nth-child(odd) span {
214 | float: left; }
215 | .filter-label {
216 | line-height: 25px; }
217 | .filters-wrapper {
218 | display: block; }
219 | .groups-wrapper .checkbox {
220 | display: none; }
221 | .groups-wrapper.show .checkbox {
222 | display: inline-block; } }
223 |
224 | body {
225 | color: #dcdcdc;
226 | background-color: #222222; }
227 |
228 | a {
229 | color: #74c7dd; }
230 | a:hover {
231 | color: #c6e8f1; }
232 |
233 | h1 a,
234 | h1 a:active,
235 | h1 a:hover {
236 | color: #a2a2a2; }
237 |
238 | .dark-mode-toggle {
239 | fill: #fff; }
240 |
241 | .services-wrapper {
242 | opacity: .8; }
243 |
244 | .checkbox-inline input[type="checkbox"]:after,
245 | .checkbox input[type="checkbox"]:after,
246 | input[type="checkbox"]:after {
247 | border-color: #2e9fbd; }
248 |
249 | .checkbox-inline input[type="checkbox"]:focus:after,
250 | .checkbox input[type="checkbox"]:focus:after,
251 | input[type="checkbox"]:focus:after {
252 | border-color: #2e9fbd; }
253 |
254 | .checkbox-inline input[type="checkbox"]:checked:after,
255 | .checkbox input[type="checkbox"]:checked:after,
256 | input[type="checkbox"]:checked:after {
257 | background-color: #2e9fbd;
258 | border-color: #2e9fbd; }
259 |
260 | .has-feedback input[role=search] {
261 | box-shadow: inset 0 -1px 0 #cbd5dd;
262 | color: #dcdcdc; }
263 | .has-feedback input[role=search]:focus {
264 | box-shadow: inset 0 -2px 0 white; }
265 | .has-feedback input[role=search]::placeholder {
266 | color: darkgray; }
267 |
268 | .panel {
269 | color: #dcdcdc;
270 | background-color: #272727; }
271 | .panel > .panel-heading {
272 | color: #beafa8;
273 | background-color: #2f2f2f; }
274 | .panel > .panel-heading .author {
275 | color: #d4cac5;
276 | font-weight: bold;
277 | font-size: 1.7rem; }
278 | .panel > .panel-heading .author .role {
279 | color: #6a6a6a;
280 | font-size: 1.2rem;
281 | display: inline-block;
282 | vertical-align: middle;
283 | margin-left: 3px; }
284 | .panel > .panel-footer {
285 | background-color: #2a2a2a; }
286 | .panel > .panel-footer .timed, .panel > .panel-footer .link {
287 | opacity: .7; }
288 | .panel > .panel-footer .timed:hover, .panel > .panel-footer .link:hover {
289 | opacity: 1; }
290 | .panel > .panel-footer .icon.comments {
291 | fill: #fff; }
292 | .panel > .panel-footer .expander {
293 | background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0, #272727);
294 | text-align: center; }
295 |
296 | .btn {
297 | color: #d4e0e4;
298 | background-color: #2e9fbd; }
299 | .btn:hover {
300 | color: #d4e0e4; }
301 |
302 | .btn-default:active:focus,
303 | .btn-default:active:hover,
304 | .btn-default:active,
305 | .btn-default:focus,
306 | .btn-default:hover {
307 | color: #d4e0e4;
308 | background: #4bb6d3; }
309 |
310 | blockquote {
311 | color: #c3c3c3;
312 | border-color: #74c7dd;
313 | opacity: .4;
314 | background-color: rgba(255, 255, 255, 0.05); }
315 | blockquote:hover {
316 | opacity: 1; }
317 |
318 | pre {
319 | color: #eeeeee;
320 | background-color: #444444;
321 | border-color: #999999;
322 | line-height: 1.4;
323 | border-radius: 1px; }
324 |
325 | iframe {
326 | border: 1px solid; }
327 |
328 | /*# sourceMappingURL=theme-dark.map */
--------------------------------------------------------------------------------
/dev/assets/theme-dark.map:
--------------------------------------------------------------------------------
1 | *::-ms-clear {
2 | height: 0;
3 | width: 0; }
4 |
5 | body {
6 | font-size: 15px;
7 | line-height: 1.5; }
8 |
9 | blockquote {
10 | font-size: inherit; }
11 |
12 | br {
13 | content: ' ';
14 | display: block;
15 | margin: 15px auto; }
16 |
17 | h1 {
18 | text-align: center; }
19 |
20 | h1 a,
21 | h1 a:active,
22 | h1 a:hover {
23 | text-decoration: none; }
24 |
25 | .header-container {
26 | position: relative; }
27 |
28 | .header-link {
29 | position: absolute;
30 | right: 15px;
31 | top: 10px; }
32 |
33 | .header-link i {
34 | font-size: 1.8em;
35 | margin: 0; }
36 |
37 | .github-link {
38 | right: 45px; }
39 |
40 | .reddit-link {
41 | right: 75px; }
42 |
43 | .twitter-link {
44 | right: 105px; }
45 |
46 | .discord-link {
47 | right: 135px; }
48 |
49 | .patreon-link {
50 | right: 165px; }
51 |
52 | .panel {
53 | position: relative;
54 | word-wrap: break-word; }
55 |
56 | .panel-footer {
57 | position: relative;
58 | padding: 3px 15px;
59 | display: flex;
60 | justify-content: space-between;
61 | align-items: center; }
62 | .panel-footer .timed {
63 | display: flex;
64 | justify-content: space-between;
65 | align-items: center; }
66 | .panel-footer .timed .icon-a {
67 | font-size: 0; }
68 |
69 | .panel-body img {
70 | max-width: 100%; }
71 |
72 | .icon {
73 | height: 25px;
74 | width: 25px; }
75 |
76 | .clearer:hover {
77 | cursor: pointer; }
78 |
79 | .expandable {
80 | max-height: 500px;
81 | overflow: hidden; }
82 |
83 | .expander {
84 | bottom: 100%;
85 | left: 15px;
86 | padding-bottom: 20px;
87 | padding-top: 60px;
88 | position: absolute;
89 | right: 0; }
90 | .expander:hover {
91 | cursor: pointer;
92 | text-decoration: underline; }
93 |
94 | input[type="checkbox"],
95 | .checkbox input[type="checkbox"] {
96 | margin-bottom: 0;
97 | margin-right: 5px; }
98 |
99 | .filter-label {
100 | height: 23px;
101 | line-height: 23px;
102 | vertical-align: top; }
103 |
104 | .services-wrapper {
105 | text-align: center; }
106 |
107 | .service-checkbox,
108 | .service-checkbox + .service-checkbox {
109 | display: inline-block;
110 | margin: 5px 20px 5px 5px; }
111 |
112 | .service-checkbox label {
113 | height: 23px;
114 | width: 100%; }
115 |
116 | .groups-wrapper {
117 | margin: 0 auto 20px auto;
118 | text-align: center;
119 | width: 1040px; }
120 |
121 | .groups-wrapper input[type="checkbox"],
122 | .groups-wrapper .checkbox input[type="checkbox"] {
123 | height: 18px;
124 | width: 18px; }
125 |
126 | .groups-wrapper .filters-wrapper svg {
127 | transition: transform 0.3s ease; }
128 |
129 | .groups-wrapper.show .filters-wrapper svg {
130 | transform: rotate(180deg); }
131 |
132 | .groups-wrapper .checkbox {
133 | display: inline-block;
134 | font-size: 12px;
135 | margin: 5px;
136 | line-height: 15px; }
137 |
138 | .groups-wrapper .checkbox label {
139 | white-space: nowrap; }
140 |
141 | .group-label {
142 | background-position: center left;
143 | background-repeat: no-repeat;
144 | display: inline-block;
145 | height: 23px;
146 | line-height: 25px;
147 | overflow: hidden;
148 | text-align: left;
149 | text-overflow: ellipsis;
150 | white-space: nowrap; }
151 |
152 | .filters-wrapper {
153 | display: none; }
154 |
155 | .adsbygoogle {
156 | display: block; }
157 |
158 | .bb-spoiler-toggle + .bb-spoiler {
159 | display: none; }
160 |
161 | .bb-spoiler-toggle.active + .bb-spoiler {
162 | display: block; }
163 |
164 | .bb-spoiler {
165 | border: 1px dashed;
166 | margin: 10px 0;
167 | padding: 10px; }
168 |
169 | a.ipsAttachLink_image {
170 | display: flex;
171 | justify-content: center; }
172 |
173 | .services-wrapper label:hover {
174 | text-decoration: underline; }
175 |
176 | .has-feedback input[role=search] {
177 | padding: 0 15px; }
178 |
179 | @media screen and (max-width: 1800px) {
180 | .adsbygoogle {
181 | display: none; } }
182 |
183 | @media screen and (max-width: 1200px) {
184 | .groups-wrapper {
185 | text-align: center;
186 | width: auto; } }
187 |
188 | @media screen and (max-width: 660px) {
189 | .header-link {
190 | display: none; } }
191 |
192 | @media screen and (max-width: 480px) {
193 | h1 {
194 | font-size: 38px; }
195 | .services-wrapper {
196 | text-align: inherit; }
197 | .service-checkbox,
198 | .service-checkbox + .service-checkbox {
199 | margin: 0;
200 | text-align: left;
201 | width: 50%; }
202 | .service-checkbox:nth-child(odd) label {
203 | padding-right: 30px;
204 | padding-left: 0; }
205 | .service-checkbox:nth-child(odd) input[type="checkbox"] {
206 | float: right;
207 | margin-left: 10px;
208 | margin-right: -25px; }
209 | .service-checkbox:nth-child(even) input[type="checkbox"] {
210 | float: left; }
211 | .service-checkbox:nth-child(even) span {
212 | float: right; }
213 | .service-checkbox:nth-child(odd) span {
214 | float: left; }
215 | .filter-label {
216 | line-height: 25px; }
217 | .filters-wrapper {
218 | display: block; }
219 | .groups-wrapper .checkbox {
220 | display: none; }
221 | .groups-wrapper.show .checkbox {
222 | display: inline-block; } }
223 |
224 | body {
225 | color: #dcdcdc;
226 | background-color: #222222; }
227 |
228 | a {
229 | color: #74c7dd; }
230 | a:hover {
231 | color: #c6e8f1; }
232 |
233 | h1 a,
234 | h1 a:active,
235 | h1 a:hover {
236 | color: #a2a2a2; }
237 |
238 | .dark-mode-toggle {
239 | fill: #fff; }
240 |
241 | .services-wrapper {
242 | opacity: .8; }
243 |
244 | .checkbox-inline input[type="checkbox"]:after,
245 | .checkbox input[type="checkbox"]:after,
246 | input[type="checkbox"]:after {
247 | border-color: #2e9fbd; }
248 |
249 | .checkbox-inline input[type="checkbox"]:focus:after,
250 | .checkbox input[type="checkbox"]:focus:after,
251 | input[type="checkbox"]:focus:after {
252 | border-color: #2e9fbd; }
253 |
254 | .checkbox-inline input[type="checkbox"]:checked:after,
255 | .checkbox input[type="checkbox"]:checked:after,
256 | input[type="checkbox"]:checked:after {
257 | background-color: #2e9fbd;
258 | border-color: #2e9fbd; }
259 |
260 | .has-feedback input[role=search] {
261 | box-shadow: inset 0 -1px 0 #cbd5dd;
262 | color: #dcdcdc; }
263 | .has-feedback input[role=search]:focus {
264 | box-shadow: inset 0 -2px 0 white; }
265 | .has-feedback input[role=search]::placeholder {
266 | color: darkgray; }
267 |
268 | .panel {
269 | color: #dcdcdc;
270 | background-color: #272727; }
271 | .panel > .panel-heading {
272 | color: #beafa8;
273 | background-color: #2f2f2f; }
274 | .panel > .panel-heading .author {
275 | color: #d4cac5;
276 | font-weight: bold;
277 | font-size: 1.7rem; }
278 | .panel > .panel-heading .author .role {
279 | color: #6a6a6a;
280 | font-size: 1.2rem;
281 | display: inline-block;
282 | vertical-align: middle;
283 | margin-left: 3px; }
284 | .panel > .panel-footer {
285 | background-color: #2a2a2a; }
286 | .panel > .panel-footer .timed, .panel > .panel-footer .link {
287 | opacity: .7; }
288 | .panel > .panel-footer .timed:hover, .panel > .panel-footer .link:hover {
289 | opacity: 1; }
290 | .panel > .panel-footer .icon.comments {
291 | fill: #fff; }
292 | .panel > .panel-footer .expander {
293 | background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0, #272727);
294 | text-align: center; }
295 |
296 | .btn {
297 | color: #d4e0e4;
298 | background-color: #2e9fbd; }
299 | .btn:hover {
300 | color: #d4e0e4; }
301 |
302 | .btn-default:active:focus,
303 | .btn-default:active:hover,
304 | .btn-default:active,
305 | .btn-default:focus,
306 | .btn-default:hover {
307 | color: #d4e0e4;
308 | background: #4bb6d3; }
309 |
310 | blockquote {
311 | color: #c3c3c3;
312 | border-color: #74c7dd;
313 | opacity: .4;
314 | background-color: rgba(255, 255, 255, 0.05); }
315 | blockquote:hover {
316 | opacity: 1; }
317 |
318 | pre {
319 | color: #eeeeee;
320 | background-color: #444444;
321 | border-color: #999999;
322 | line-height: 1.4;
323 | border-radius: 1px; }
324 |
325 | iframe {
326 | border: 1px solid; }
327 |
328 | /*# sourceMappingURL=theme-dark.map */
--------------------------------------------------------------------------------
/dev/assets/theme-light.css:
--------------------------------------------------------------------------------
1 | *::-ms-clear {
2 | height: 0;
3 | width: 0; }
4 |
5 | body {
6 | font-size: 15px;
7 | line-height: 1.5; }
8 |
9 | blockquote {
10 | font-size: inherit; }
11 |
12 | br {
13 | content: ' ';
14 | display: block;
15 | margin: 15px auto; }
16 |
17 | h1 {
18 | text-align: center; }
19 |
20 | h1 a,
21 | h1 a:active,
22 | h1 a:hover {
23 | text-decoration: none; }
24 |
25 | .header-container {
26 | position: relative; }
27 |
28 | .header-link {
29 | position: absolute;
30 | right: 15px;
31 | top: 10px; }
32 |
33 | .header-link i {
34 | font-size: 1.8em;
35 | margin: 0; }
36 |
37 | .github-link {
38 | right: 45px; }
39 |
40 | .reddit-link {
41 | right: 75px; }
42 |
43 | .twitter-link {
44 | right: 105px; }
45 |
46 | .discord-link {
47 | right: 135px; }
48 |
49 | .patreon-link {
50 | right: 165px; }
51 |
52 | .panel {
53 | position: relative;
54 | word-wrap: break-word; }
55 |
56 | .panel-footer {
57 | position: relative;
58 | padding: 3px 15px;
59 | display: flex;
60 | justify-content: space-between;
61 | align-items: center; }
62 | .panel-footer .timed {
63 | display: flex;
64 | justify-content: space-between;
65 | align-items: center; }
66 | .panel-footer .timed .icon-a {
67 | font-size: 0; }
68 |
69 | .panel-body img {
70 | max-width: 100%; }
71 |
72 | .icon {
73 | height: 25px;
74 | width: 25px; }
75 |
76 | .clearer:hover {
77 | cursor: pointer; }
78 |
79 | .expandable {
80 | max-height: 500px;
81 | overflow: hidden; }
82 |
83 | .expander {
84 | bottom: 100%;
85 | left: 15px;
86 | padding-bottom: 20px;
87 | padding-top: 60px;
88 | position: absolute;
89 | right: 0; }
90 | .expander:hover {
91 | cursor: pointer;
92 | text-decoration: underline; }
93 |
94 | input[type="checkbox"],
95 | .checkbox input[type="checkbox"] {
96 | margin-bottom: 0;
97 | margin-right: 5px; }
98 |
99 | .filter-label {
100 | height: 23px;
101 | line-height: 23px;
102 | vertical-align: top; }
103 |
104 | .services-wrapper {
105 | text-align: center; }
106 |
107 | .service-checkbox,
108 | .service-checkbox + .service-checkbox {
109 | display: inline-block;
110 | margin: 5px 20px 5px 5px; }
111 |
112 | .service-checkbox label {
113 | height: 23px;
114 | width: 100%; }
115 |
116 | .groups-wrapper {
117 | margin: 0 auto 20px auto;
118 | text-align: center;
119 | width: 1040px; }
120 |
121 | .groups-wrapper input[type="checkbox"],
122 | .groups-wrapper .checkbox input[type="checkbox"] {
123 | height: 18px;
124 | width: 18px; }
125 |
126 | .groups-wrapper .filters-wrapper svg {
127 | transition: transform 0.3s ease; }
128 |
129 | .groups-wrapper.show .filters-wrapper svg {
130 | transform: rotate(180deg); }
131 |
132 | .groups-wrapper .checkbox {
133 | display: inline-block;
134 | font-size: 12px;
135 | margin: 5px;
136 | line-height: 15px; }
137 |
138 | .groups-wrapper .checkbox label {
139 | white-space: nowrap; }
140 |
141 | .group-label {
142 | background-position: center left;
143 | background-repeat: no-repeat;
144 | display: inline-block;
145 | height: 23px;
146 | line-height: 25px;
147 | overflow: hidden;
148 | text-align: left;
149 | text-overflow: ellipsis;
150 | white-space: nowrap; }
151 |
152 | .filters-wrapper {
153 | display: none; }
154 |
155 | .adsbygoogle {
156 | display: block; }
157 |
158 | .bb-spoiler-toggle + .bb-spoiler {
159 | display: none; }
160 |
161 | .bb-spoiler-toggle.active + .bb-spoiler {
162 | display: block; }
163 |
164 | .bb-spoiler {
165 | border: 1px dashed;
166 | margin: 10px 0;
167 | padding: 10px; }
168 |
169 | a.ipsAttachLink_image {
170 | display: flex;
171 | justify-content: center; }
172 |
173 | .services-wrapper label:hover {
174 | text-decoration: underline; }
175 |
176 | .has-feedback input[role=search] {
177 | padding: 0 15px; }
178 |
179 | @media screen and (max-width: 1800px) {
180 | .adsbygoogle {
181 | display: none; } }
182 |
183 | @media screen and (max-width: 1200px) {
184 | .groups-wrapper {
185 | text-align: center;
186 | width: auto; } }
187 |
188 | @media screen and (max-width: 660px) {
189 | .header-link {
190 | display: none; } }
191 |
192 | @media screen and (max-width: 480px) {
193 | h1 {
194 | font-size: 38px; }
195 | .services-wrapper {
196 | text-align: inherit; }
197 | .service-checkbox,
198 | .service-checkbox + .service-checkbox {
199 | margin: 0;
200 | text-align: left;
201 | width: 50%; }
202 | .service-checkbox:nth-child(odd) label {
203 | padding-right: 30px;
204 | padding-left: 0; }
205 | .service-checkbox:nth-child(odd) input[type="checkbox"] {
206 | float: right;
207 | margin-left: 10px;
208 | margin-right: -25px; }
209 | .service-checkbox:nth-child(even) input[type="checkbox"] {
210 | float: left; }
211 | .service-checkbox:nth-child(even) span {
212 | float: right; }
213 | .service-checkbox:nth-child(odd) span {
214 | float: left; }
215 | .filter-label {
216 | line-height: 25px; }
217 | .filters-wrapper {
218 | display: block; }
219 | .groups-wrapper .checkbox {
220 | display: none; }
221 | .groups-wrapper.show .checkbox {
222 | display: inline-block; } }
223 |
224 | h1 a,
225 | h1 a:active,
226 | h1 a:hover {
227 | color: #000; }
228 |
229 | #icon-rss rect {
230 | fill: #2196f3; }
231 |
232 | #icon-reddit rect {
233 | fill: #666; }
234 |
235 | #icon-twitter rect {
236 | fill: #666; }
237 |
238 | #icon-comments {
239 | fill: #666; }
240 |
241 | #icon-caret {
242 | fill: #666; }
243 |
244 | .expander {
245 | background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, white 40%, white 100%);
246 | color: #2196F3; }
247 |
248 | .bb-spoiler {
249 | border-color: #ccc; }
250 |
251 | /*# sourceMappingURL=theme-light.map */
--------------------------------------------------------------------------------
/dev/assets/theme-light.map:
--------------------------------------------------------------------------------
1 | *::-ms-clear {
2 | height: 0;
3 | width: 0; }
4 |
5 | body {
6 | font-size: 15px;
7 | line-height: 1.5; }
8 |
9 | blockquote {
10 | font-size: inherit; }
11 |
12 | br {
13 | content: ' ';
14 | display: block;
15 | margin: 15px auto; }
16 |
17 | h1 {
18 | text-align: center; }
19 |
20 | h1 a,
21 | h1 a:active,
22 | h1 a:hover {
23 | text-decoration: none; }
24 |
25 | .header-container {
26 | position: relative; }
27 |
28 | .header-link {
29 | position: absolute;
30 | right: 15px;
31 | top: 10px; }
32 |
33 | .header-link i {
34 | font-size: 1.8em;
35 | margin: 0; }
36 |
37 | .github-link {
38 | right: 45px; }
39 |
40 | .reddit-link {
41 | right: 75px; }
42 |
43 | .twitter-link {
44 | right: 105px; }
45 |
46 | .discord-link {
47 | right: 135px; }
48 |
49 | .patreon-link {
50 | right: 165px; }
51 |
52 | .panel {
53 | position: relative;
54 | word-wrap: break-word; }
55 |
56 | .panel-footer {
57 | position: relative;
58 | padding: 3px 15px;
59 | display: flex;
60 | justify-content: space-between;
61 | align-items: center; }
62 | .panel-footer .timed {
63 | display: flex;
64 | justify-content: space-between;
65 | align-items: center; }
66 | .panel-footer .timed .icon-a {
67 | font-size: 0; }
68 |
69 | .panel-body img {
70 | max-width: 100%; }
71 |
72 | .icon {
73 | height: 25px;
74 | width: 25px; }
75 |
76 | .clearer:hover {
77 | cursor: pointer; }
78 |
79 | .expandable {
80 | max-height: 500px;
81 | overflow: hidden; }
82 |
83 | .expander {
84 | bottom: 100%;
85 | left: 15px;
86 | padding-bottom: 20px;
87 | padding-top: 60px;
88 | position: absolute;
89 | right: 0; }
90 | .expander:hover {
91 | cursor: pointer;
92 | text-decoration: underline; }
93 |
94 | input[type="checkbox"],
95 | .checkbox input[type="checkbox"] {
96 | margin-bottom: 0;
97 | margin-right: 5px; }
98 |
99 | .filter-label {
100 | height: 23px;
101 | line-height: 23px;
102 | vertical-align: top; }
103 |
104 | .services-wrapper {
105 | text-align: center; }
106 |
107 | .service-checkbox,
108 | .service-checkbox + .service-checkbox {
109 | display: inline-block;
110 | margin: 5px 20px 5px 5px; }
111 |
112 | .service-checkbox label {
113 | height: 23px;
114 | width: 100%; }
115 |
116 | .groups-wrapper {
117 | margin: 0 auto 20px auto;
118 | text-align: center;
119 | width: 1040px; }
120 |
121 | .groups-wrapper input[type="checkbox"],
122 | .groups-wrapper .checkbox input[type="checkbox"] {
123 | height: 18px;
124 | width: 18px; }
125 |
126 | .groups-wrapper .filters-wrapper svg {
127 | transition: transform 0.3s ease; }
128 |
129 | .groups-wrapper.show .filters-wrapper svg {
130 | transform: rotate(180deg); }
131 |
132 | .groups-wrapper .checkbox {
133 | display: inline-block;
134 | font-size: 12px;
135 | margin: 5px;
136 | line-height: 15px; }
137 |
138 | .groups-wrapper .checkbox label {
139 | white-space: nowrap; }
140 |
141 | .group-label {
142 | background-position: center left;
143 | background-repeat: no-repeat;
144 | display: inline-block;
145 | height: 23px;
146 | line-height: 25px;
147 | overflow: hidden;
148 | text-align: left;
149 | text-overflow: ellipsis;
150 | white-space: nowrap; }
151 |
152 | .filters-wrapper {
153 | display: none; }
154 |
155 | .adsbygoogle {
156 | display: block; }
157 |
158 | .bb-spoiler-toggle + .bb-spoiler {
159 | display: none; }
160 |
161 | .bb-spoiler-toggle.active + .bb-spoiler {
162 | display: block; }
163 |
164 | .bb-spoiler {
165 | border: 1px dashed;
166 | margin: 10px 0;
167 | padding: 10px; }
168 |
169 | a.ipsAttachLink_image {
170 | display: flex;
171 | justify-content: center; }
172 |
173 | .services-wrapper label:hover {
174 | text-decoration: underline; }
175 |
176 | .has-feedback input[role=search] {
177 | padding: 0 15px; }
178 |
179 | @media screen and (max-width: 1800px) {
180 | .adsbygoogle {
181 | display: none; } }
182 |
183 | @media screen and (max-width: 1200px) {
184 | .groups-wrapper {
185 | text-align: center;
186 | width: auto; } }
187 |
188 | @media screen and (max-width: 660px) {
189 | .header-link {
190 | display: none; } }
191 |
192 | @media screen and (max-width: 480px) {
193 | h1 {
194 | font-size: 38px; }
195 | .services-wrapper {
196 | text-align: inherit; }
197 | .service-checkbox,
198 | .service-checkbox + .service-checkbox {
199 | margin: 0;
200 | text-align: left;
201 | width: 50%; }
202 | .service-checkbox:nth-child(odd) label {
203 | padding-right: 30px;
204 | padding-left: 0; }
205 | .service-checkbox:nth-child(odd) input[type="checkbox"] {
206 | float: right;
207 | margin-left: 10px;
208 | margin-right: -25px; }
209 | .service-checkbox:nth-child(even) input[type="checkbox"] {
210 | float: left; }
211 | .service-checkbox:nth-child(even) span {
212 | float: right; }
213 | .service-checkbox:nth-child(odd) span {
214 | float: left; }
215 | .filter-label {
216 | line-height: 25px; }
217 | .filters-wrapper {
218 | display: block; }
219 | .groups-wrapper .checkbox {
220 | display: none; }
221 | .groups-wrapper.show .checkbox {
222 | display: inline-block; } }
223 |
224 | h1 a,
225 | h1 a:active,
226 | h1 a:hover {
227 | color: #000; }
228 |
229 | #icon-rss rect {
230 | fill: #2196f3; }
231 |
232 | #icon-reddit rect {
233 | fill: #666; }
234 |
235 | #icon-twitter rect {
236 | fill: #666; }
237 |
238 | #icon-comments {
239 | fill: #666; }
240 |
241 | #icon-caret {
242 | fill: #666; }
243 |
244 | .expander {
245 | background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, white 40%, white 100%);
246 | color: #2196F3; }
247 |
248 | .bb-spoiler {
249 | border-color: #ccc; }
250 |
251 | /*# sourceMappingURL=theme-light.map */
--------------------------------------------------------------------------------
/games/ark/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/ark/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/ark/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/ark/android-chrome-512x512.png
--------------------------------------------------------------------------------
/games/ark/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/ark/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/ark/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/ark/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/ark/favicon-16x16.png
--------------------------------------------------------------------------------
/games/ark/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/ark/favicon-32x32.png
--------------------------------------------------------------------------------
/games/ark/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/ark/favicon.ico
--------------------------------------------------------------------------------
/games/ark/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/ark/mstile-150x150.png
--------------------------------------------------------------------------------
/games/ark/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Ark Dev Tracker",
3 | "short_name": "Ark Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone",
19 | "start_url": "./?utm_source=homescreen"
20 | }
21 |
--------------------------------------------------------------------------------
/games/battlefield1/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/battlefield1/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/battlefield1/assets/logo-dice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/assets/logo-dice.png
--------------------------------------------------------------------------------
/games/battlefield1/assets/logo-ea.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/assets/logo-ea.png
--------------------------------------------------------------------------------
/games/battlefield1/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/assets/logo.png
--------------------------------------------------------------------------------
/games/battlefield1/assets/purista-medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/assets/purista-medium.woff
--------------------------------------------------------------------------------
/games/battlefield1/assets/purista-medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/assets/purista-medium.woff2
--------------------------------------------------------------------------------
/games/battlefield1/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/battlefield1/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/favicon-16x16.png
--------------------------------------------------------------------------------
/games/battlefield1/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/favicon-32x32.png
--------------------------------------------------------------------------------
/games/battlefield1/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/favicon.ico
--------------------------------------------------------------------------------
/games/battlefield1/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/battlefield1/mstile-150x150.png
--------------------------------------------------------------------------------
/games/battlefield1/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "BF Dev Tracker",
3 | "short_name": "BF Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "theme_color": "#ffffff",
12 | "background_color": "#2c2d30",
13 | "display": "standalone",
14 | "start_url": "./?utm_source=homescreen"
15 | }
16 |
--------------------------------------------------------------------------------
/games/battlefield1/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-light";
2 |
3 | @font-face {
4 | font-family: 'Purista';
5 | src: url( 'assets/purista-medium.woff2' ) format( 'woff2' ),
6 | url( 'assets/purista-medium.woff' ) format( 'woff' );
7 | font-weight: normal;
8 | font-style: normal;
9 | font-display: swap;
10 | }
11 |
12 | body {
13 | background-color: #2c2d30;
14 | color: #fff;
15 | font-family: Purista, Roboto, serif;
16 | }
17 |
18 | h1 {
19 | text-transform: uppercase;
20 | }
21 |
22 | h1 a,
23 | h1 a:active,
24 | h1 a:hover {
25 | color: #fff;
26 | }
27 |
28 | a,
29 | a:focus,
30 | a:hover,
31 | a:active {
32 | color: #f17f1a;
33 | }
34 |
35 | #icon-rss rect {
36 | fill: #f17f1a;
37 | }
38 |
39 | #icon-reddit rect {
40 | fill: #f17f1a;
41 | }
42 |
43 | #icon-twitter rect {
44 | fill: #f17f1a;
45 | }
46 |
47 | #icon-comments {
48 | fill: #f17f1a;
49 | }
50 |
51 | #icon-caret {
52 | fill: #f17f1a;
53 | }
54 |
55 | .header-logo {
56 | max-height: 42px;
57 | position: relative;
58 | top: -5px;
59 | }
60 |
61 | .group-label.ea {
62 | background-image: url( 'assets/logo-ea.png' );
63 | text-indent: -9999px;
64 | width: 50px;
65 | }
66 |
67 | .group-label.dice {
68 | background-image: url( 'assets/logo-dice.png' );
69 | text-indent: -9999px;
70 | width: 50px;
71 | }
72 |
73 | .panel {
74 | background-color: #131313;
75 | border-radius: 0;
76 | box-shadow: 0 1px 29px rgb(0, 0, 0);
77 | }
78 |
79 | .panel-footer {
80 | background-color: #1a1a1a;
81 | }
82 |
83 | .panel-default>.panel-heading {
84 | color: #fff;
85 | background-color: #1a1a1a;
86 | }
87 |
88 | .form-control {
89 | color: #fff;
90 | }
91 |
92 | .expander {
93 | background: linear-gradient(
94 | to bottom,
95 | rgba( 19, 19, 17, 0 ) 0%,
96 | rgba( 19, 19, 17, 1 ) 40%,
97 | rgba( 19, 19, 17, 1 ) 100%
98 | );
99 | }
100 |
101 | @media screen and ( max-width: 1040px ){
102 | .groups-wrapper .checkbox {
103 | width: 80px;
104 | }
105 | }
106 |
107 | @media screen and ( max-width: 480px ){
108 | .header-logo {
109 | display: block;
110 | margin: 0 auto;
111 | max-height: 38px;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/games/conan/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/conan/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/conan/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/conan/android-chrome-512x512.png
--------------------------------------------------------------------------------
/games/conan/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/conan/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/conan/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/conan/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/conan/favicon-16x16.png
--------------------------------------------------------------------------------
/games/conan/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/conan/favicon-32x32.png
--------------------------------------------------------------------------------
/games/conan/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/conan/favicon.ico
--------------------------------------------------------------------------------
/games/conan/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/conan/mstile-150x150.png
--------------------------------------------------------------------------------
/games/conan/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Conan Dev Tracker",
3 | "short_name": "Conan Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone",
19 | "start_url": "./?utm_source=homescreen"
20 | }
21 |
--------------------------------------------------------------------------------
/games/conan/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-dark";
2 |
3 | img.emoji {
4 | max-width: 20px;
5 | position: relative;
6 | top: -2px;
7 | }
8 |
--------------------------------------------------------------------------------
/games/conan/theme-light.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-light";
2 |
3 | img.emoji {
4 | max-width: 20px;
5 | position: relative;
6 | top: -2px;
7 | }
8 |
--------------------------------------------------------------------------------
/games/csgo/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/csgo/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/csgo/assets/CounterStrike.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/CounterStrike.woff
--------------------------------------------------------------------------------
/games/csgo/assets/CounterStrike.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/CounterStrike.woff2
--------------------------------------------------------------------------------
/games/csgo/assets/flairs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/flairs.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-cloud9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-cloud9.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-complexity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-complexity.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-counter-logic-gaming.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-counter-logic-gaming.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-dreamhack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-dreamhack.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-dropthebomb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-dropthebomb.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-echo-fox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-echo-fox.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-eleague.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-eleague.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-epicenter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-epicenter.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-espn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-espn.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-godsent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-godsent.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-hellraisers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-hellraisers.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-misfits.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-misfits.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-mousesports.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-mousesports.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-ninjas-in-pyjamas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-ninjas-in-pyjamas.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-oddshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-oddshot.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-optic-gaming.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-optic-gaming.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-renegades.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-renegades.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-rfrsh-entertainment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-rfrsh-entertainment.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-selfless-gaming.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-selfless-gaming.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-splyce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-splyce.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-team-solomid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-team-solomid.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-twitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-twitch.png
--------------------------------------------------------------------------------
/games/csgo/assets/logo-wesa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/assets/logo-wesa.png
--------------------------------------------------------------------------------
/games/csgo/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/csgo/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/favicon-16x16.png
--------------------------------------------------------------------------------
/games/csgo/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/favicon-32x32.png
--------------------------------------------------------------------------------
/games/csgo/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/favicon.ico
--------------------------------------------------------------------------------
/games/csgo/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/csgo/mstile-150x150.png
--------------------------------------------------------------------------------
/games/csgo/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
31 |
--------------------------------------------------------------------------------
/games/csgo/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CSGO Dev Tracker",
3 | "short_name": "CSGO Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "theme_color": "#ffffff",
12 | "background_color": "#ffffff",
13 | "display": "standalone",
14 | "start_url": "./?utm_source=homescreen"
15 | }
16 |
--------------------------------------------------------------------------------
/games/dayz/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-dark";
--------------------------------------------------------------------------------
/games/dayz/theme-light.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-light";
2 |
--------------------------------------------------------------------------------
/games/destiny/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/destiny/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/destiny/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/destiny/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/destiny/assets/destiny-font.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/destiny/assets/destiny-font.woff
--------------------------------------------------------------------------------
/games/destiny/assets/destiny-font.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/destiny/assets/destiny-font.woff2
--------------------------------------------------------------------------------
/games/destiny/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/destiny/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/destiny/favicon-16x16.png
--------------------------------------------------------------------------------
/games/destiny/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/destiny/favicon-32x32.png
--------------------------------------------------------------------------------
/games/destiny/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/destiny/favicon.ico
--------------------------------------------------------------------------------
/games/destiny/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/destiny/mstile-150x150.png
--------------------------------------------------------------------------------
/games/destiny/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
67 |
--------------------------------------------------------------------------------
/games/destiny/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Destiny Dev Tracker",
3 | "short_name": "Destiny Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "theme_color": "#ffffff",
12 | "background_color": "#ffffff",
13 | "display": "standalone",
14 | "start_url": "./?utm_source=homescreen"
15 | }
16 |
--------------------------------------------------------------------------------
/games/destiny/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-dark";
2 |
3 | @font-face {
4 | font-family: 'Destiny';
5 | font-weight: normal;
6 | font-style: normal;
7 | src: url( 'assets/destiny-font.woff2' ) format( 'woff2' ),
8 | url( 'assets/destiny-font.woff' ) format( 'woff' );
9 | font-display: swap;
10 | }
11 |
12 | body {
13 | font-family: Destiny, Roboto, serif;
14 | }
15 |
--------------------------------------------------------------------------------
/games/destiny/theme-light.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-light";
2 |
3 | @font-face {
4 | font-family: 'Destiny';
5 | font-weight: normal;
6 | font-style: normal;
7 | src: url( 'assets/destiny-font.woff2' ) format( 'woff2' ),
8 | url( 'assets/destiny-font.woff' ) format( 'woff' );
9 | font-display: swap;
10 | }
11 |
12 | body {
13 | font-family: Destiny, Roboto, serif;
14 | }
15 |
--------------------------------------------------------------------------------
/games/elite/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/elite/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/elite/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/elite/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/elite/assets/eurostile.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/elite/assets/eurostile.woff
--------------------------------------------------------------------------------
/games/elite/assets/eurostile.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/elite/assets/eurostile.woff2
--------------------------------------------------------------------------------
/games/elite/assets/loader.svg:
--------------------------------------------------------------------------------
1 |
134 |
--------------------------------------------------------------------------------
/games/elite/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/elite/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/elite/favicon-16x16.png
--------------------------------------------------------------------------------
/games/elite/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/elite/favicon-32x32.png
--------------------------------------------------------------------------------
/games/elite/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/elite/favicon.ico
--------------------------------------------------------------------------------
/games/elite/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/elite/mstile-150x150.png
--------------------------------------------------------------------------------
/games/elite/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
100 |
--------------------------------------------------------------------------------
/games/elite/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Elite Dev Tracker",
3 | "short_name": "Elite Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "theme_color": "#ffffff",
12 | "background_color": "#ffffff",
13 | "display": "standalone",
14 | "start_url": "./?utm_source=homescreen"
15 | }
16 |
--------------------------------------------------------------------------------
/games/elite/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-dark";
2 |
3 | @font-face {
4 | font-family: 'Eurostile';
5 | font-style: normal;
6 | font-weight: normal;
7 | src: url( 'assets/eurostile.woff2' ) format( 'woff2' ),
8 | url( 'assets/eurostile.woff' ) format( 'woff' );
9 | font-display: swap;
10 | }
11 |
12 | body {
13 | font-family: Eurostile, Roboto, serif;
14 | }
15 |
16 | h1 {
17 | text-transform: uppercase;
18 | }
19 |
--------------------------------------------------------------------------------
/games/elite/theme-light.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-light";
2 |
3 | @font-face {
4 | font-family: 'Eurostile';
5 | font-style: normal;
6 | font-weight: normal;
7 | src: url( 'assets/eurostile.woff2' ) format( 'woff2' ),
8 | url( 'assets/eurostile.woff' ) format( 'woff' );
9 | font-display: swap;
10 | }
11 |
12 | body {
13 | font-family: Eurostile, Roboto, serif;
14 | }
15 |
16 | h1 {
17 | text-transform: uppercase;
18 | }
19 |
--------------------------------------------------------------------------------
/games/escape-from-tarkov/theme-dark.scss:
--------------------------------------------------------------------------------
1 | $fc-link: #827356;
2 | $fc-head: #dad1b6;
3 | $fc-btxt: #d4e0e4;
4 | $fc-srch: #dcdcdc;
5 | $bs-srch: #c5b88e;
6 | $fc-main: #c5b88e;
7 | $bg-main: #0e0e0e;
8 | $bg-pres: #444444;
9 | $bc-pres: #999999;
10 | $fc-pres: #eeeeee;
11 | $bc-quot: #827356;
12 | $fc-serv: #827356;
13 |
14 | $fc-h1tx: #c5b88e;
15 | $fc-auth: lighten($fc-head, 10%);
16 | $fc-role: mix($fc-auth, #000, 70%);
17 | $bg-head: #21211f;
18 | $bg-pane: #171715;
19 | $bg-foot: #171715;
20 | $bg-post: #5f5440;
21 | $fc-quot: $fc-main;
22 | $bg-chck: $bg-post;
23 |
24 | @import "../../web-assets/theme-dark";
25 |
26 | .services-wrapper {
27 | color: $fc-serv;
28 | }
29 |
30 | iframe {
31 | border: 1px solid;
32 | }
33 |
34 | .header-link {
35 | opacity: .7;
36 |
37 | &:hover {
38 | opacity: 1;
39 | }
40 | }
41 |
42 | .panel svg.icon,
43 | img.loader {
44 | filter: sepia(100%);
45 | }
46 |
--------------------------------------------------------------------------------
/games/fortnite/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/fortnite/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/android-chrome-512x512.png
--------------------------------------------------------------------------------
/games/fortnite/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/fortnite/assets/BurbankBigCondensed-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/assets/BurbankBigCondensed-Bold.woff
--------------------------------------------------------------------------------
/games/fortnite/assets/BurbankBigCondensed-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/assets/BurbankBigCondensed-Bold.woff2
--------------------------------------------------------------------------------
/games/fortnite/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/fortnite/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/favicon-16x16.png
--------------------------------------------------------------------------------
/games/fortnite/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/favicon-32x32.png
--------------------------------------------------------------------------------
/games/fortnite/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/favicon.ico
--------------------------------------------------------------------------------
/games/fortnite/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/fortnite/mstile-150x150.png
--------------------------------------------------------------------------------
/games/fortnite/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Fortnite Dev Tracker",
3 | "icons": [
4 | {
5 | "src": "/android-chrome-192x192.png",
6 | "sizes": "192x192",
7 | "type": "image/png"
8 | },
9 | {
10 | "src": "/android-chrome-512x512.png",
11 | "sizes": "512x512",
12 | "type": "image/png"
13 | }
14 | ],
15 | "theme_color": "#ffffff",
16 | "background_color": "#ffffff",
17 | "display": "standalone"
18 | }
--------------------------------------------------------------------------------
/games/fortnite/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-dark";
2 |
3 | @import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');
4 |
5 | @font-face {
6 | font-family: 'Burbank Big Condensed';
7 | font-style: normal;
8 | font-weight: bold;
9 | src: url('BurbankBigCondensed-Bold.woff2') format('woff2'),
10 | url('BurbankBigCondensed-Bold.woff') format('woff');
11 | font-display: swap;
12 | }
13 |
14 | body {
15 | font-family: 'Open Sans', serif;
16 | }
17 |
18 | h1 {
19 | font-family: 'Burbank Big Condensed', serif;
20 | font-weight: bold;
21 | }
22 |
--------------------------------------------------------------------------------
/games/fortnite/theme-light.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-light";
2 |
3 | @import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');
4 |
5 | @font-face {
6 | font-family: 'Burbank Big Condensed';
7 | font-style: normal;
8 | font-weight: bold;
9 | src: url('BurbankBigCondensed-Bold.woff2') format('woff2'),
10 | url('BurbankBigCondensed-Bold.woff') format('woff');
11 | font-display: swap;
12 | }
13 |
14 | body {
15 | font-family: 'Open Sans', serif;
16 | }
17 |
18 | h1 {
19 | font-family: 'Burbank Big Condensed', serif;
20 | font-weight: bold;
21 | }
22 |
--------------------------------------------------------------------------------
/games/pubg/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/pubg/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/pubg/android-chrome-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/pubg/android-chrome-256x256.png
--------------------------------------------------------------------------------
/games/pubg/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/pubg/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/pubg/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/pubg/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/pubg/favicon-16x16.png
--------------------------------------------------------------------------------
/games/pubg/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/pubg/favicon-32x32.png
--------------------------------------------------------------------------------
/games/pubg/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/pubg/favicon.ico
--------------------------------------------------------------------------------
/games/pubg/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/pubg/mstile-150x150.png
--------------------------------------------------------------------------------
/games/pubg/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PUBG Dev Tracker",
3 | "short_name": "PUBG Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./android-chrome-256x256.png",
12 | "sizes": "256x256",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone",
19 | "start_url": "./?utm_source=homescreen"
20 | }
21 |
--------------------------------------------------------------------------------
/games/rainbow6/assets/logo-esl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rainbow6/assets/logo-esl.png
--------------------------------------------------------------------------------
/games/rainbow6/assets/logo-ubisoft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rainbow6/assets/logo-ubisoft.png
--------------------------------------------------------------------------------
/games/rainbow6/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-dark";
2 |
3 | .group-label.esl {
4 | background-image: url( 'assets/logo-esl.png' );
5 | text-indent: -9999px;
6 | width: 50px;
7 | }
8 |
9 | .group-label.ubisoft {
10 | background-image: url( 'assets/logo-ubisoft.png' );
11 | text-indent: -9999px;
12 | width: 50px;
13 | }
14 |
--------------------------------------------------------------------------------
/games/rainbow6/theme-light.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-light";
2 |
3 | .group-label.esl {
4 | background-image: url( 'assets/logo-esl.png' );
5 | text-indent: -9999px;
6 | width: 50px;
7 | }
8 |
9 | .group-label.ubisoft {
10 | background-image: url( 'assets/logo-ubisoft.png' );
11 | text-indent: -9999px;
12 | width: 50px;
13 | }
14 |
--------------------------------------------------------------------------------
/games/rimworld/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rimworld/android-chrome-192x192.png
--------------------------------------------------------------------------------
/games/rimworld/android-chrome-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rimworld/android-chrome-256x256.png
--------------------------------------------------------------------------------
/games/rimworld/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rimworld/apple-touch-icon.png
--------------------------------------------------------------------------------
/games/rimworld/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/games/rimworld/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rimworld/favicon-16x16.png
--------------------------------------------------------------------------------
/games/rimworld/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rimworld/favicon-32x32.png
--------------------------------------------------------------------------------
/games/rimworld/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rimworld/favicon.ico
--------------------------------------------------------------------------------
/games/rimworld/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/games/rimworld/mstile-150x150.png
--------------------------------------------------------------------------------
/games/rimworld/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
144 |
--------------------------------------------------------------------------------
/games/rimworld/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "RimWorld Dev Tracker",
3 | "short_name": "RimWorld Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "./android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./android-chrome-256x256.png",
12 | "sizes": "256x256",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone",
19 | "start_url": "./?utm_source=homescreen"
20 | }
21 |
--------------------------------------------------------------------------------
/games/star-citizen/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-dark";
2 |
3 | @import url('https://fonts.googleapis.com/css?family=Orbitron');
4 |
5 | h1 {
6 | font-family: 'Orbitron', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/games/star-citizen/theme-light.scss:
--------------------------------------------------------------------------------
1 | @import "../../web-assets/theme-light";
2 |
3 | @import url('https://fonts.googleapis.com/css?family=Orbitron');
4 |
5 | h1 {
6 | font-family: 'Orbitron', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "site",
3 | "version": "2.0.0",
4 | "description": "A framework for running multiple dev trackers",
5 | "main": "index.html",
6 | "scripts": {
7 | "stage": "node scripts/build.js --stage && npx serve stage",
8 | "build": "webpack --mode=production --progress",
9 | "deploy": "node scripts/build.js",
10 | "dev": "concurrently \"webpack-dev-server --open\" \"nodemon --watch web-assets --watch games -e scss scripts/buildstyles.js\"",
11 | "lint:components": "eslint -c kokarn/react app/**/*",
12 | "lint:scripts": "eslint -c kokarn/nodejs scripts/*.js",
13 | "pretest": "eslint *.js"
14 | },
15 | "author": "Oskar Risberg
",
16 | "repository": {
17 | "type": "git",
18 | "url": "https://kokarn@github.com/post-tracker/site.git"
19 | },
20 | "bugs": {
21 | "url": "https://github.com/post-tracker/site/issues"
22 | },
23 | "license": "MIT",
24 | "dependencies": {
25 | "@babel/preset-env": "^7.18.2",
26 | "@babel/preset-react": "^7.17.12",
27 | "@redux-devtools/core": "^3.13.1",
28 | "aws-sdk": "^2.562.0",
29 | "babel-core": "^6.26.3",
30 | "babel-loader": "^8.2.5",
31 | "babel-preset-env": "^1.7.0",
32 | "babel-preset-react": "^6.24.1",
33 | "concurrently": "^7.0.0",
34 | "cssnano": "^3.10.0",
35 | "debounce": "^1.2.0",
36 | "dotenv": "^16.0.0",
37 | "eslint": "^3.5.0",
38 | "eslint-config-kokarn": "^2.0.0",
39 | "junk": "^3.1.0",
40 | "minimist": "^1.2.0",
41 | "mustache": "^2.3.2",
42 | "node-sass": "^7.0.1",
43 | "nodemon": "^2.0.15",
44 | "postcss": "^6.0.23",
45 | "prop-types": "^15.7.2",
46 | "react": "^18.2.0",
47 | "react-cookie": "^1.0.5",
48 | "react-dom": "^18.2.0",
49 | "react-redux": "^8.0.2",
50 | "react-timeago": "^7.1.0",
51 | "react-toggle-dark-mode": "^1.1.0",
52 | "recursive-readdir": "^2.2.2",
53 | "redux": "^4.0.4",
54 | "redux-thunk": "^2.3.0",
55 | "rss": "^1.2.2",
56 | "webpack": "^5.72.1",
57 | "webpack-cli": "^4.9.2",
58 | "webpack-dev-server": "^4.9.0"
59 | },
60 | "eslintConfig": {
61 | "extends": "kokarn"
62 | },
63 | "engines": {
64 | "node": "^18.0.0"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/scripts/build.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-sync */
2 | require( 'dotenv' ).config();
3 |
4 | const path = require( 'path' );
5 | const https = require( 'https' );
6 | const url = require( 'url' );
7 | const fs = require( 'fs' );
8 |
9 | const mustache = require( 'mustache' );
10 | const junk = require( 'junk' );
11 | const recursive = require( 'recursive-readdir' );
12 | const argv = require( 'minimist' )( process.argv.slice( 2 ) );
13 |
14 | const gamecss = require( './modules/gamecss' );
15 | const savefile = require( './modules/savefile' );
16 | const sleep = require('./modules/sleep');
17 |
18 | if ( !process.env.API_TOKEN ) {
19 | throw new Error( 'Unable to load api key' );
20 | }
21 |
22 | const API_HOST = 'api.developertracker.com';
23 | const STAGE_PATH = path.join( __dirname, '..', 'stage' );
24 | // const API_HOST = 'localhost:3000';
25 | // process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
26 |
27 | const promiseGet = function promiseGet( requestUrl, headers = false ) {
28 | return new Promise( ( resolve, reject ) => {
29 | let httpsGet = requestUrl;
30 | if ( headers ) {
31 | const urlParts = url.parse( requestUrl );
32 |
33 | httpsGet = {
34 | headers: headers,
35 | hostname: urlParts.hostname,
36 | path: urlParts.path,
37 | port: urlParts.port || 443,
38 | };
39 | }
40 |
41 | console.log( `Loading ${ requestUrl }` );
42 |
43 | const request = https.get( httpsGet, ( response ) => {
44 | if ( response.statusCode < 200 || response.statusCode > 299 ) {
45 | reject( new Error( `Failed to load ${ requestUrl }, status code: ${ response.statusCode }` ) );
46 | }
47 |
48 | const body = [];
49 |
50 | console.log( `Done with ${ requestUrl }` );
51 |
52 | response.on( 'data', ( chunk ) => {
53 | body.push( chunk );
54 | } );
55 |
56 | response.on( 'end', () => {
57 | resolve( body.join( '' ) );
58 | } );
59 | } );
60 |
61 | request.on( 'error', ( requestError ) => {
62 | reject( requestError );
63 | } );
64 | } );
65 | };
66 |
67 | const getGames = async function getGames() {
68 | let allGamesConfig;
69 | const gamesConfig = {};
70 |
71 | try {
72 | const gamesConfigResponse = await promiseGet( `https://${ API_HOST }/games`, {
73 | Authorization: `Bearer ${ process.env.API_TOKEN }`,
74 | } );
75 | allGamesConfig = JSON.parse( gamesConfigResponse );
76 | } catch ( getGamesError ) {
77 | console.log( `Unable to load games. Got "${ getGamesError.message }"` );
78 |
79 | throw getGamesError;
80 | }
81 |
82 | allGamesConfig.data.forEach( ( gameConfig ) => {
83 | gamesConfig[ gameConfig.identifier ] = gameConfig;
84 | } );
85 |
86 | return gamesConfig;
87 | };
88 |
89 | const buildGame = function buildGame( gameData ) {
90 | console.log( `Building ${ gameData.identifier }` );
91 | const gameFilesPath = path.join( __dirname, '..', 'games', gameData.identifier );
92 | const rewriteFiles = [
93 | 'index.html',
94 | 'service-worker.js',
95 | ];
96 | const dataRootPath = path.join( __dirname, '..', 'web' );
97 |
98 | // Upload all default files
99 | recursive( dataRootPath, ( readDirError, files ) => {
100 | if ( readDirError ) {
101 | throw readDirError;
102 | }
103 |
104 | fileLoop:
105 | for ( const file of files ) {
106 | if ( junk.is( path.parse( file ).base ) ) {
107 | continue;
108 | }
109 | const fileName = path.join( gameData.identifier, file.replace( dataRootPath, '' ) )
110 |
111 | // Don't upload files we'll rewrite
112 | for ( const rewriteFile of rewriteFiles ) {
113 | if ( fileName.includes( rewriteFile ) ) {
114 | continue fileLoop;
115 | }
116 | }
117 |
118 | savefile( fileName, fs.readFileSync( file ) );
119 | }
120 | } );
121 |
122 | savefile( path.join( gameData.identifier, '/assets/theme-dark.min.css' ), gameData.themeDark );
123 | savefile( path.join( gameData.identifier, '/assets/theme-light.min.css' ), gameData.themeLight );
124 |
125 | recursive( gameFilesPath, ( gameFilesError, gameFiles ) => {
126 | if ( gameFilesError ) {
127 | console.log( `No game files found for ${ gameData.identifier } ` );
128 | gameFiles = [];
129 | }
130 |
131 | for ( const filename of gameFiles ) {
132 | if ( junk.is( path.parse( filename ).base ) ) {
133 | continue;
134 | }
135 |
136 | if ( filename.includes( 'styles.css' ) ) {
137 | gameData.styles = fs.readFileSync( filename );
138 | }
139 |
140 | if ( filename.includes( 'assets/logo.png' ) ) {
141 | gameData.logo = '';
142 | }
143 |
144 | savefile( path.join( gameData.identifier, filename.replace( gameFilesPath, '' ) ), fs.readFileSync( filename ) );
145 | }
146 |
147 | if ( !gameData.logo ) {
148 | gameData.logo = gameData.shortName;
149 | }
150 |
151 | for ( let i = 0; i < rewriteFiles.length; i = i + 1 ) {
152 | // Fill in the data where needed
153 | fs.readFile( path.join( dataRootPath, rewriteFiles[ i ] ), 'utf8', ( readFileError, fileData ) => {
154 | if ( readFileError ) {
155 | console.error( readFileError );
156 |
157 | return false;
158 | }
159 |
160 | savefile( path.join( gameData.identifier, rewriteFiles[ i ] ), mustache.render( fileData, gameData ) );
161 |
162 | return true;
163 | } );
164 | }
165 | } );
166 |
167 | console.log( `Build ${ gameData.identifier } done` );
168 | };
169 |
170 | const buildRootPage = function buildRootPage( gamesData ){
171 | const allGamesTemplate = fs.readFileSync( path.join( __dirname, '..', 'web-assets', 'games-template.html' ), 'utf8' );
172 | const games = Object.values( gamesData );
173 | const renderData = {
174 | games: [],
175 | };
176 |
177 | games.sort( ( a, b ) => {
178 | return a.name.localeCompare( b.name );
179 | } );
180 |
181 | for ( let i = 0; i < games.length; i = i + 1 ) {
182 | // Don't build games set as not live
183 | if ( !games[ i ].config || games[ i ].config.live === 0 || games[ i ].config.live === false ) {
184 | continue;
185 | }
186 |
187 | let name = games[ i ].name;
188 | let url = games[ i ].hostname;
189 | let image = games[ i ].config.boxart;
190 |
191 | if ( url === 'developertracker.com' ) {
192 | url = `${ url }/${ games[ i ].identifier }/`
193 | }
194 |
195 | renderData.games.push( {
196 | url,
197 | image,
198 | name,
199 | } );
200 | }
201 |
202 | savefile( 'index.html', mustache.render( allGamesTemplate, renderData ) );
203 | };
204 |
205 | const run = async function run() {
206 | let games;
207 |
208 | if ( argv.stage ) {
209 | try {
210 | fs.rmSync( STAGE_PATH, {
211 | recursive: true,
212 | } );
213 | } catch( removeError ) {
214 | console.error( removeError );
215 | }
216 | }
217 |
218 | try {
219 | games = await getGames();
220 | } catch ( loadGamesError ) {
221 | console.error( 'Failed to load games from the API, not building' );
222 |
223 | return false;
224 | }
225 | const addGameProperty = function addGameProperty( property, value ) {
226 | for ( const identifier in games ) {
227 | games[ identifier ][ property ] = value;
228 | }
229 | };
230 | addGameProperty( 'version', Date.now() );
231 | addGameProperty( 'defaultTheme', 'light' );
232 |
233 | const servicePromises = [];
234 |
235 | for ( const identifier in games ) {
236 | const servicePromise = promiseGet( `https://${ API_HOST }/${ identifier }/services` )
237 | .then( ( servicesResponse ) => {
238 | let services = JSON.parse( servicesResponse ).data;
239 |
240 | // If we only have one service, treat it as none
241 | if ( services.length === 1 ) {
242 | services = [];
243 | }
244 |
245 | // Transform service names to objects
246 | services = services.map( ( name ) => {
247 | let label = name;
248 | if ( games[ identifier ].config && games[ identifier ].config.sources && games[ identifier ].config.sources[ name ] ) {
249 | label = games[ identifier ].config.sources[ name ].label || name;
250 | }
251 |
252 | return {
253 | active: true,
254 | name: name,
255 | label: label,
256 | };
257 | } );
258 |
259 | services.sort( ( a,b ) => {
260 | return a.label.localeCompare( b.label );
261 | } );
262 |
263 | games[ identifier ].services = JSON.stringify( services );
264 | } )
265 | .catch( ( serviceError ) => {
266 | throw serviceError;
267 | } );
268 |
269 | servicePromises.push( servicePromise );
270 | await sleep(500);
271 | }
272 |
273 | const groupPromises = [];
274 |
275 | for ( const identifier in games ) {
276 | const groupPromise = promiseGet( `https://${ API_HOST }/${ identifier }/groups` )
277 | .then( ( groupsResponse ) => {
278 | let groups = JSON.parse( groupsResponse ).data;
279 |
280 | // If we only have one group, treat it as none
281 | if ( groups.length === 1 ) {
282 | groups = [];
283 | }
284 |
285 | // Transform group names to objects
286 | groups = groups.map( ( name ) => {
287 | return {
288 | active: true,
289 | name: name,
290 | };
291 | } );
292 |
293 | games[ identifier ].groups = JSON.stringify( groups );
294 | } )
295 | .catch( ( groupError ) => {
296 | throw groupError;
297 | } );
298 |
299 | groupPromises.push( groupPromise );
300 | await sleep(500);
301 | }
302 |
303 | for ( const identifier in games ) {
304 | games[ identifier ].themeDark = gamecss( identifier, 'dark' );
305 | games[ identifier ].themeLight = gamecss( identifier, 'light' );
306 |
307 | if ( games[ identifier ].config && games[ identifier ].config.defaultTheme ) {
308 | games[ identifier ].defaultTheme = games[ identifier ].config.defaultTheme;
309 | }
310 | }
311 |
312 | Promise.all( [
313 | Promise.all( servicePromises ),
314 | Promise.all( groupPromises ),
315 | ] )
316 | .then( () => {
317 | for ( const gameIdentifier in games ) {
318 | buildGame( games[ gameIdentifier ] );
319 | }
320 |
321 | buildRootPage( games );
322 | } )
323 | .catch( ( chainError ) => {
324 | throw chainError;
325 | } );
326 | };
327 |
328 | run();
329 |
--------------------------------------------------------------------------------
/scripts/buildstyles.js:
--------------------------------------------------------------------------------
1 | const path = require( 'path' );
2 | const fs = require( 'fs' );
3 | const https = require( 'https' );
4 |
5 | const gamecss = require( './modules/gamecss' );
6 |
7 | const promiseGet = function promiseGet( requestUrl ) {
8 | return new Promise( ( resolve, reject ) => {
9 | console.log( `Loading ${ requestUrl }` );
10 |
11 | const request = https.get( requestUrl, ( response ) => {
12 | if ( response.statusCode < 200 || response.statusCode > 299 ) {
13 | reject( new Error( `Failed to load ${ requestUrl }, status code: ${ response.statusCode }` ) );
14 | }
15 |
16 | const body = [];
17 |
18 | console.log( `Done with ${ requestUrl }` );
19 |
20 | response.on( 'data', ( chunk ) => {
21 | body.push( chunk );
22 | } );
23 |
24 | response.on( 'end', () => {
25 | resolve( body.join( '' ) );
26 | } );
27 | } );
28 |
29 | request.on( 'error', ( requestError ) => {
30 | reject( requestError );
31 | } );
32 | } );
33 | };
34 |
35 | const writeStyle = function writeStyle( identifier, type ) {
36 | const writePath = path.join( __dirname, '..', 'dev', identifier );
37 | const gameStyles = gamecss( identifier, type );
38 |
39 | try {
40 | fs.mkdirSync( writePath );
41 | } catch ( createDirError ) {
42 | // We don't care if it already exists
43 | }
44 |
45 | fs.writeFileSync( path.join( writePath, `theme-${ type }.css` ), gameStyles );
46 | fs.writeFileSync( path.join( writePath, `theme-${ type }.map` ), gameStyles );
47 | };
48 |
49 | promiseGet( 'https://api.developertracker.com/games' )
50 | .then( ( gamesBody ) => {
51 | const games = JSON.parse( gamesBody );
52 | writeStyle( 'assets', 'light' );
53 | writeStyle( 'assets', 'dark' );
54 |
55 | for ( const game of games.data ) {
56 | writeStyle( game.identifier, 'light' );
57 | writeStyle( game.identifier, 'dark' );
58 | }
59 | } )
60 | .catch( ( requestError ) => {
61 | throw requestError;
62 | } );
63 |
--------------------------------------------------------------------------------
/scripts/modules/gamecss.js:
--------------------------------------------------------------------------------
1 | const path = require( 'path' );
2 | const fs = require( 'fs' );
3 | const https = require( 'https' );
4 |
5 | const sass = require( 'node-sass' );
6 | const postcss = require( 'postcss' );
7 | const cssnano = require( 'cssnano' );
8 |
9 | const LIGHT_SOURCE_FILE = path.join( __dirname, '..', '..', 'web-assets', 'theme-light.scss' );
10 | const DARK_SOURCE_FILE = path.join( __dirname, '..', '..', 'web-assets', 'theme-dark.scss' );
11 |
12 | module.exports = function( game, type, targetFolder ) {
13 | const lightBaseResult = sass.renderSync( {
14 | file: LIGHT_SOURCE_FILE,
15 | sourceMap: true,
16 | outFile: path.join( path.dirname( LIGHT_SOURCE_FILE ), 'theme-light' ),
17 | } );
18 |
19 | const darkBaseResult = sass.renderSync( {
20 | file: DARK_SOURCE_FILE,
21 | sourceMap: true,
22 | outFile: path.join( path.dirname( DARK_SOURCE_FILE ), 'theme-dark' ),
23 | } );
24 |
25 | const baseStyles = {
26 | 'dark': darkBaseResult.css.toString(),
27 | 'light': lightBaseResult.css.toString(),
28 | };
29 | let gameStyles = false;
30 |
31 | try {
32 | const gameSassResult = sass.renderSync( {
33 | file: path.join( __dirname, '..', '..', 'games', game, `theme-${ type }.scss` ),
34 | sourceMap: true,
35 | } );
36 |
37 | if ( gameSassResult ) {
38 | gameStyles = gameSassResult.css.toString();
39 | }
40 | } catch( readError ) {
41 | // We don't care if we can't read it
42 | if ( readError.status !== 3 ) {
43 | console.log( readError );
44 | }
45 | }
46 |
47 | if ( !gameStyles ) {
48 | gameStyles = baseStyles[ type ];
49 | }
50 |
51 | postcss([cssnano])
52 | .process(gameStyles, { from: 'src/app.css', to: 'dest/app.css' })
53 | .then(result => {
54 | fs.writeFile('dest/app.css', result.css, () => true)
55 | if ( result.map ) {
56 | fs.writeFile('dest/app.css.map', result.map, () => true)
57 | }
58 | })
59 |
60 | return gameStyles;
61 | };
62 |
--------------------------------------------------------------------------------
/scripts/modules/savefile.js:
--------------------------------------------------------------------------------
1 | require( 'dotenv' ).config();
2 |
3 | const path = require( 'path' );
4 | const fs = require( 'fs' );
5 |
6 | const mime = require( 'mime-types' );
7 | const AWS = require( 'aws-sdk' );
8 | const argv = require( 'minimist' )( process.argv.slice( 2 ) );
9 |
10 | if ( !process.env.AWS_ACCESS_KEY || !process.env.AWS_SECRET_KEY ) {
11 | throw new Error( 'AWS auth not configured' );
12 | }
13 |
14 | const S3_BUCKET = 'developer-tracker';
15 | const STAGE_PATH = path.join( __dirname, '..', '..', 'stage' );
16 |
17 | const s3 = new AWS.S3( {
18 | accessKeyId: process.env.AWS_ACCESS_KEY,
19 | secretAccessKey: process.env.AWS_SECRET_KEY,
20 | } );
21 |
22 | const cacheControls = [
23 | {
24 | match: 'service-worker.js',
25 | cache: 'public, max-age=600, must-revalidate',
26 | },
27 | {
28 | match: '.*\.html',
29 | cache: 'public, max-age=600',
30 | },
31 | {
32 | match: '.*\.css',
33 | cache: 'public, max-age=31536000',
34 | },
35 | {
36 | match: '.*\.js',
37 | cache: 'public, max-age=31536000',
38 | },
39 | {
40 | match: '\.(jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff|woff2)',
41 | cache: 'public, max-age=2678400',
42 | },
43 | {
44 | match: '\.(json|xml)',
45 | cache: 'public, max-age=2678400',
46 | },
47 | ];
48 |
49 | const getCache = function getCache ( filePath ) {
50 | const filename = path.parse( filePath ).base;
51 |
52 | for ( const cacheSetup of cacheControls ) {
53 | const regex = new RegExp( cacheSetup.match );
54 |
55 | if ( regex.test( filePath ) ) {
56 | return cacheSetup.cache;
57 | }
58 | }
59 |
60 | console.error( `No cache for ${ filename }` );
61 |
62 | return false;
63 | };
64 |
65 | module.exports = function saveFile( filePath, fileData ) {
66 | const params = {
67 | Bucket: S3_BUCKET,
68 | Key: filePath,
69 | Body: fileData,
70 | CacheControl: getCache( filePath ),
71 | ContentType: mime.lookup( filePath ),
72 | };
73 |
74 | if ( argv.stage ) {
75 | const fullPath = path.join( STAGE_PATH, filePath );
76 |
77 | fs.mkdir( path.parse( fullPath ).dir, {
78 | recursive: true,
79 | }, ( writeError ) => {
80 | if ( writeError ) {
81 | throw writeError;
82 | }
83 |
84 | fs.writeFileSync( fullPath, fileData );
85 | } );
86 | } else {
87 | s3.putObject( params, ( uploadError, data ) => {
88 | if ( uploadError ) {
89 | console.error( uploadError )
90 | } else {
91 | console.log( `Successfully uploaded ${ filePath } to ${ S3_BUCKET }` );
92 | }
93 | } );
94 | }
95 | };
96 |
--------------------------------------------------------------------------------
/scripts/modules/sleep.js:
--------------------------------------------------------------------------------
1 | module.exports = function sleep(ms) {
2 | return new Promise(resolve => setTimeout(resolve, ms));
3 | };
4 |
--------------------------------------------------------------------------------
/web-assets/_styles.scss:
--------------------------------------------------------------------------------
1 | *::-ms-clear {
2 | height: 0;
3 | width : 0;
4 | }
5 |
6 | body {
7 | font-size: 15px;
8 | line-height: 1.5;
9 | }
10 |
11 | blockquote {
12 | font-size: inherit;
13 | }
14 |
15 | br {
16 | content: ' ';
17 | display: block;
18 | margin: 15px auto;
19 | }
20 |
21 | h1 {
22 | text-align: center;
23 | }
24 |
25 | h1 a,
26 | h1 a:active,
27 | h1 a:hover {
28 | text-decoration: none;
29 | }
30 |
31 | .header-container {
32 | position: relative;
33 | }
34 |
35 | .header-link {
36 | position: absolute;
37 | right: 15px;
38 | top: 10px;
39 | }
40 |
41 | .header-link i {
42 | font-size: 1.8em;
43 | margin: 0;
44 | }
45 |
46 | .github-link {
47 | right: 45px;
48 | }
49 |
50 | .reddit-link {
51 | right: 75px;
52 | }
53 |
54 | .twitter-link {
55 | right: 105px;
56 | }
57 |
58 | .discord-link {
59 | right: 135px;
60 | }
61 |
62 | .patreon-link {
63 | right: 165px;
64 | }
65 |
66 | .panel {
67 | position: relative;
68 | word-wrap: break-word;
69 | }
70 |
71 | .panel-footer {
72 | position: relative;
73 | padding: 3px 15px;
74 | display: flex;
75 | justify-content: space-between;
76 | align-items: center;
77 |
78 | .timed {
79 | display: flex;
80 | justify-content: space-between;
81 | align-items: center;
82 |
83 | .icon-a {
84 | font-size: 0;
85 | }
86 | }
87 | }
88 |
89 | .panel-body img {
90 | max-width: 100%;
91 | }
92 |
93 | .icon {
94 | height: 25px;
95 | width: 25px;
96 | }
97 |
98 | .clearer:hover {
99 | cursor: pointer;
100 | }
101 |
102 | .expandable {
103 | max-height: 500px;
104 | overflow: hidden;
105 | }
106 |
107 | .expander {
108 | bottom: 100%;
109 | left: 15px;
110 | padding-bottom: 20px;
111 | padding-top: 60px;
112 | position: absolute;
113 | right: 0;
114 |
115 | &:hover {
116 | cursor: pointer;
117 | text-decoration: underline;
118 | }
119 | }
120 |
121 | input[type="checkbox"],
122 | .checkbox input[type="checkbox"] {
123 | margin-bottom: 0;
124 | margin-right: 5px;
125 | }
126 |
127 | .filter-label {
128 | height: 23px;
129 | line-height: 23px;
130 | vertical-align: top;
131 | }
132 |
133 | .services-wrapper {
134 | text-align: center;
135 | }
136 |
137 | .service-checkbox,
138 | .service-checkbox+.service-checkbox {
139 | display: inline-block;
140 | margin: 5px 20px 5px 5px;
141 | }
142 |
143 | .service-checkbox label {
144 | height: 23px;
145 | width: 100%;
146 | }
147 |
148 | .groups-wrapper {
149 | margin: 0 auto 20px auto;
150 | text-align: center;
151 | width: 1040px;
152 | }
153 |
154 | .groups-wrapper input[type="checkbox"],
155 | .groups-wrapper .checkbox input[type="checkbox"] {
156 | height: 18px;
157 | width: 18px;
158 | }
159 |
160 | .groups-wrapper .filters-wrapper svg {
161 | transition: transform 0.3s ease;
162 | }
163 |
164 | .groups-wrapper.show .filters-wrapper svg {
165 | transform: rotate( 180deg );
166 | }
167 |
168 | .groups-wrapper .checkbox {
169 | display: inline-block;
170 | font-size: 12px;
171 | margin: 5px;
172 | line-height: 15px;
173 | }
174 |
175 | .groups-wrapper .checkbox label {
176 | white-space: nowrap;
177 | }
178 |
179 | .group-label {
180 | background-position: center left;
181 | background-repeat: no-repeat;
182 | display: inline-block;
183 | height: 23px;
184 | line-height: 25px;
185 | overflow: hidden;
186 | text-align: left;
187 | text-overflow: ellipsis;
188 | white-space: nowrap;
189 | }
190 |
191 | .filters-wrapper {
192 | display: none;
193 | }
194 |
195 | .adsbygoogle {
196 | display: block;
197 | }
198 |
199 | .bb-spoiler-toggle + .bb-spoiler {
200 | display: none;
201 | }
202 |
203 | .bb-spoiler-toggle.active + .bb-spoiler {
204 | display: block;
205 | }
206 |
207 | .bb-spoiler {
208 | border: 1px dashed;
209 | margin: 10px 0;
210 | padding: 10px;
211 | }
212 |
213 | a.ipsAttachLink_image {
214 | display: flex;
215 | justify-content: center;
216 | }
217 |
218 | .services-wrapper {
219 | label:hover {
220 | text-decoration: underline;
221 | }
222 | }
223 |
224 | @media screen and ( max-width: 1800px ){
225 | .adsbygoogle {
226 | display: none;
227 | }
228 | }
229 |
230 | @media screen and ( max-width: 1200px ){
231 | h1 {
232 | margin-top: 35px;
233 | }
234 |
235 | .groups-wrapper {
236 | text-align: center;
237 | width: auto;
238 | }
239 | }
240 |
241 | @media screen and ( max-width: 660px ){
242 | .header-link {
243 | display: none;
244 | }
245 | }
246 |
247 | @media screen and ( max-width: 480px ){
248 | h1 {
249 | font-size: 38px;
250 | }
251 |
252 | .services-wrapper {
253 | text-align: inherit;
254 | }
255 |
256 | .service-checkbox,
257 | .service-checkbox + .service-checkbox {
258 | margin: 0;
259 | text-align: left;
260 | width: 50%;
261 | }
262 |
263 | .service-checkbox:nth-child( odd ) label {
264 | padding-right: 30px;
265 | padding-left: 0;
266 | }
267 |
268 | .service-checkbox:nth-child( odd ) input[type="checkbox"] {
269 | float: right;
270 | margin-left: 10px;
271 | margin-right: -25px;
272 | }
273 |
274 | .service-checkbox:nth-child( even ) input[type="checkbox"] {
275 | float: left;
276 | }
277 |
278 | .service-checkbox:nth-child( even ) span {
279 | float: right;
280 | }
281 |
282 | .service-checkbox:nth-child( odd ) span {
283 | float: left;
284 | }
285 |
286 | .filter-label {
287 | line-height: 25px;
288 | }
289 |
290 | .filters-wrapper {
291 | display: block;
292 | }
293 |
294 | .groups-wrapper .checkbox {
295 | display: none;
296 | }
297 |
298 | .groups-wrapper.show .checkbox {
299 | display: inline-block;
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/web-assets/games-template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Developer Tracker
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
81 |
82 |
83 |
84 | Developer Trackers
85 |
86 |
89 |
90 | Add to Discord
91 |
92 |
93 |
94 | {{#games}}
95 |
101 | {{/games}}
102 |
103 |
104 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/web-assets/theme-dark.scss:
--------------------------------------------------------------------------------
1 | @import "_styles";
2 |
3 | $fc-link: #74c7dd !default;
4 | $fc-head: #beafa8 !default;
5 | $fc-btxt: #d4e0e4 !default;
6 | $fc-srch: #dcdcdc !default;
7 | $bs-srch: #cbd5dd !default;
8 | $fc-main: #dcdcdc !default;
9 | $bg-main: #222222 !default;
10 | $bg-pres: #444444 !default;
11 | $bc-pres: #999999 !default;
12 | $fc-pres: #eeeeee !default;
13 | $bc-quot: $fc-link !default;
14 |
15 | $fc-h1tx: lighten($bg-main, 50%) !default;
16 | $fc-auth: lighten($fc-head, 10%) !default;
17 | $bg-head: lighten($bg-main, 5%) !default;
18 | $bg-pane: lighten($bg-main, 2%) !default;
19 | $fc-role: lighten($bg-pres, 15%) !default;
20 | $bg-foot: darken($bg-head, 2%) !default;
21 | $bg-post: darken($fc-link, 20%) !default;
22 | $fc-quot: darken($fc-main, 10%) !default;
23 | $bg-chck: $bg-post;
24 |
25 | body {
26 | color: $fc-main;
27 | background-color: $bg-main;
28 | }
29 |
30 | a {
31 | color: $fc-link;
32 |
33 | &:hover {
34 | color: lighten($fc-link, 20%);
35 | }
36 | }
37 |
38 | h1 a,
39 | h1 a:active,
40 | h1 a:hover {
41 | color: $fc-h1tx;
42 | }
43 |
44 | .dark-mode-toggle {
45 | fill: #fff;
46 | }
47 |
48 | .services-wrapper {
49 | opacity: .8;
50 | }
51 |
52 | .checkbox-inline input[type="checkbox"]:after,
53 | .checkbox input[type="checkbox"]:after,
54 | input[type="checkbox"]:after {
55 | border-color: $bg-chck;
56 | }
57 |
58 | .checkbox-inline input[type="checkbox"]:focus:after,
59 | .checkbox input[type="checkbox"]:focus:after,
60 | input[type="checkbox"]:focus:after {
61 | border-color: $bg-chck;
62 | }
63 |
64 | .checkbox-inline input[type="checkbox"]:checked:after,
65 | .checkbox input[type="checkbox"]:checked:after,
66 | input[type="checkbox"]:checked:after {
67 | background-color: $bg-chck;
68 | border-color: $bg-chck;
69 | }
70 |
71 | .has-feedback input[role=search] {
72 | box-shadow: inset 0px -2px 0px -1px $bs-srch;
73 | color: $fc-srch;
74 |
75 | &:focus {
76 | box-shadow: inset 0 -2px 0 lighten($fc-srch, 20%);
77 | }
78 |
79 | &::placeholder {
80 | color: darken($fc-srch, 20%);
81 | }
82 | }
83 |
84 | .panel {
85 | color: $fc-main;
86 | background-color: $bg-pane;
87 |
88 | > .panel-heading {
89 | color: $fc-head;
90 | background-color: $bg-head;
91 |
92 | .author {
93 | color: $fc-auth;
94 | font-weight: bold;
95 | font-size: 1.7rem;
96 |
97 | .role {
98 | color: $fc-role;
99 | font-size: 1.2rem;
100 | display: inline-block;
101 | vertical-align: middle;
102 | margin-left: 3px;
103 | }
104 | }
105 | }
106 |
107 | > .panel-footer {
108 | background-color: $bg-foot;
109 |
110 | .timed, .link {
111 | opacity: .7;
112 |
113 | &:hover {
114 | opacity: 1;
115 | }
116 | }
117 |
118 | .icon {
119 | &.comments {
120 | fill: #fff;
121 | }
122 | }
123 |
124 | .expander {
125 | background: linear-gradient(180deg, hsla(0, 0%, 100%, 0) 0, $bg-pane);
126 | text-align: center;
127 | }
128 | }
129 | }
130 |
131 | .btn {
132 | color: $fc-btxt;
133 | background-color: $bg-post;
134 |
135 | &:hover {
136 | color: $fc-btxt;
137 | }
138 | }
139 |
140 | .btn-default:active:focus,
141 | .btn-default:active:hover,
142 | .btn-default:active,
143 | .btn-default:focus,
144 | .btn-default:hover {
145 | color: $fc-btxt;
146 | background: lighten($bg-post, 10%);
147 | }
148 |
149 | blockquote {
150 | color: $fc-quot;
151 | border-color: $bc-quot;
152 | opacity: .4;
153 | background-color: rgba(255, 255, 255, .05);
154 |
155 | &:hover {
156 | opacity: 1;
157 | }
158 | }
159 |
160 | pre {
161 | color: $fc-pres;
162 | background-color: $bg-pres;
163 | border-color: $bc-pres;
164 | line-height: 1.4;
165 | border-radius: 1px;
166 | }
167 |
168 | iframe {
169 | border: 1px solid;
170 | }
171 |
172 | .groups-wrapper .filters-wrapper svg {
173 | fill: #fff;
174 | }
--------------------------------------------------------------------------------
/web-assets/theme-light.scss:
--------------------------------------------------------------------------------
1 | @import "_styles";
2 |
3 | h1 a,
4 | h1 a:active,
5 | h1 a:hover {
6 | color: #000;
7 | }
8 |
9 | #icon-rss rect {
10 | fill: #2196f3;
11 | }
12 |
13 | #icon-reddit rect {
14 | fill: #666;
15 | }
16 |
17 | #icon-twitter rect {
18 | fill: #666;
19 | }
20 |
21 | #icon-comments {
22 | fill: #666;
23 | }
24 |
25 | #icon-caret {
26 | fill: #666;
27 | }
28 |
29 | #icon-discord rect {
30 | fill: #666;
31 | }
32 |
33 | .expander {
34 | background: linear-gradient(
35 | to bottom,
36 | rgba( 255, 255, 255, 0 ) 0%,
37 | rgba( 255, 255, 255, 1 ) 40%,
38 | rgba( 255, 255, 255, 1 ) 100%
39 | );
40 | color: #2196F3;
41 | }
42 |
43 | .bb-spoiler {
44 | border-color: #ccc;
45 | }
46 |
--------------------------------------------------------------------------------
/web/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/web/android-chrome-192x192.png
--------------------------------------------------------------------------------
/web/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/web/android-chrome-512x512.png
--------------------------------------------------------------------------------
/web/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/web/apple-touch-icon.png
--------------------------------------------------------------------------------
/web/assets/loader.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/web/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/web/favicon-16x16.png
--------------------------------------------------------------------------------
/web/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/web/favicon-32x32.png
--------------------------------------------------------------------------------
/web/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/web/favicon.ico
--------------------------------------------------------------------------------
/web/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/post-tracker/site/f8828f83c8bdb3e767185735f1a63b43303868c8/web/mstile-150x150.png
--------------------------------------------------------------------------------
/web/service-worker.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2016 Google Inc. All Rights Reserved.
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 | http://www.apache.org/licenses/LICENSE-2.0
7 | Unless required by applicable law or agreed to in writing, software
8 | distributed under the License is distributed on an "AS IS" BASIS,
9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | See the License for the specific language governing permissions and
11 | limitations under the License.
12 | */
13 |
14 | // Names of the two caches used in this version of the service worker.
15 | // Change to v2, etc. when you update any of the local resources, which will
16 | // in turn trigger the install event again.
17 | const ASSET_CACHE = 'precache-{{version}}';
18 |
19 | // A list of local resources we always want to be cached.
20 | const PRECACHE_ASSETS = [
21 | 'index.html',
22 | './',
23 | './assets/styles.min.css?v={{version}}',
24 | './assets/loader.svg?v=2',
25 | './scripts/app.js?v={{version}}',
26 | './assets/bootstrap.min.css?v=3.3.7'
27 | ];
28 |
29 | const cacheOrNetwork = function cacheOrNetwork( event ) {
30 | event.respondWith(
31 | caches.match( event.request )
32 | .then( ( cachedResponse ) => {
33 | if ( cachedResponse ) {
34 | return cachedResponse;
35 | }
36 |
37 | return fetch( event.request )
38 | .then( ( response ) => {
39 | return response;
40 | } );
41 | } )
42 | );
43 | };
44 |
45 | // The install handler takes care of precaching the resources we always need.
46 | self.addEventListener( 'install', ( event ) => {
47 | event.waitUntil(
48 | caches.open( ASSET_CACHE )
49 | .then( ( cache ) => {
50 | cache.addAll( PRECACHE_ASSETS );
51 | } )
52 | .then( self.skipWaiting() )
53 | .catch( ( someError ) => {
54 | console.log( someError ) ;
55 | } )
56 | );
57 | } );
58 |
59 | // The activate handler takes care of cleaning up old caches.
60 | self.addEventListener( 'activate', ( event ) => {
61 | const currentCaches = [
62 | ASSET_CACHE,
63 | ];
64 |
65 | event.waitUntil(
66 | caches.keys()
67 | .then( ( cacheNames ) => {
68 | return cacheNames.filter( ( cacheName ) => {
69 | return !currentCaches.includes( cacheName );
70 | } );
71 | } )
72 | .then( ( cachesToDelete ) => {
73 | return Promise.all( cachesToDelete.map( ( cacheToDelete ) => {
74 | return caches.delete( cacheToDelete );
75 | } ) );
76 | } )
77 | .then( () => {
78 | self.clients.claim();
79 | } )
80 | .catch( ( someError ) => {
81 | console.log( someError );
82 | } )
83 | );
84 | } );
85 |
86 | self.addEventListener( 'fetch', ( event ) => {
87 | if ( event.request.url.startsWith( self.location.origin ) ) {
88 | cacheOrNetwork( event );
89 | }
90 | } );
91 |
--------------------------------------------------------------------------------
/web/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Developer Tracker",
3 | "short_name": "Dev Tracker",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone",
19 | "start_url": "./?utm_source=homescreen"
20 | }
21 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require( 'path' );
2 |
3 | const defaultRewrite = function ( path, req ) {
4 | return '/index.html';
5 | };
6 |
7 | const assetsRewrite = function ( path, req ) {
8 | if (
9 | path.match( '/assets/theme-light.css' ) ||
10 | path.match( '/assets/theme-dark.css' ) ||
11 | path.match( '/assets/theme-light.map' ) ||
12 | path.match( '/assets/theme-dark.map' )
13 | ) {
14 | return path.replace( '/assets', '' );
15 | }
16 |
17 | const matches = path.match( /\/.+?(\/.*)/ );
18 |
19 | return matches[ 1 ];
20 | };
21 |
22 | module.exports = {
23 | entry: './app/index.jsx',
24 | mode: 'development',
25 | module: {
26 | rules: [
27 | {
28 | exclude: /(node_modules)/,
29 | test: /\.jsx?$/,
30 | use: {
31 | loader: 'babel-loader',
32 | options: {
33 | presets: [
34 | '@babel/env',
35 | '@babel/react',
36 | ],
37 | },
38 | },
39 | },
40 | ],
41 | },
42 | devtool: 'source-map',
43 | devServer: {
44 | https: true,
45 | host: '0.0.0.0',
46 | port: 9000,
47 | devMiddleware: {
48 | publicPath: "https://0.0.0.0:9000/scripts/",
49 | },
50 | static: {
51 | directory: path.join( __dirname, 'dev' ),
52 | watch: true,
53 | },
54 | proxy: {
55 | '/*/*.html': {
56 | target: 'https://0.0.0.0:9000',
57 | secure: false,
58 | pathRewrite: defaultRewrite,
59 | },
60 | '/*/': {
61 | target: 'https://0.0.0.0:9000',
62 | secure: false,
63 | pathRewrite: defaultRewrite,
64 | },
65 | '/*/assets/**': {
66 | target: 'https://0.0.0.0:9000',
67 | secure: false,
68 | pathRewrite: assetsRewrite,
69 | },
70 | '/*/scripts/dev.js': {
71 | target: 'https://0.0.0.0:9000',
72 | secure: false,
73 | pathRewrite: {
74 | '^/.*/scripts': '/assets'
75 | },
76 | },
77 | '/scripts/dev.js': {
78 | target: 'https://0.0.0.0:9000',
79 | secure: false,
80 | pathRewrite: {
81 | '^/scripts': '/assets'
82 | },
83 | },
84 | '/*/scripts/app.js': {
85 | target: 'https://0.0.0.0:9000',
86 | secure: false,
87 | pathRewrite: {
88 | '^/.*/scripts': '/scripts'
89 | },
90 | },
91 | },
92 | },
93 | output: {
94 | filename: 'app.js',
95 | path: path.resolve( __dirname, 'web/scripts' ),
96 | },
97 | resolve: {
98 | extensions: [
99 | '.js',
100 | '.jsx',
101 | ],
102 | },
103 | };
104 |
--------------------------------------------------------------------------------