Compare commits

...

70 Commits

Author SHA1 Message Date
sigonasr2, Sig, Sigo 97e98a0b14
Create App.js 3 years ago
sigonasr2, Sig, Sigo ddf4bd236a
Update App.js 3 years ago
sigonasr2, Sig, Sigo 3567a68871
Update main.yml 3 years ago
sigonasr2, Sig, Sigo 0c531040c5
Create main.yml 3 years ago
Rawrington 3c0181ab12 Merge branch 'master' of https://github.com/Rawrington/SkillDisplay 4 years ago
Rawrington 419c8322b8 fixed sanity check! im bad! 4 years ago
Rawrington 3506b65505
Merge pull request #53 from Rawrington/dependabot/npm_and_yarn/react-and-react-dom-17.0.1 4 years ago
Rawrington 7836d6775d lazy fix 4 years ago
dependabot-preview[bot] 89cb364080
Bump react and react-dom 4 years ago
Rawrington b9eae69630 Update package-lock.json 4 years ago
Rawrington 75f7496ea9
Merge pull request #46 from Rawrington/dependabot/npm_and_yarn/react-16.14.0 4 years ago
Rawrington 0b8565870e
Merge pull request #50 from Rawrington/dependabot/npm_and_yarn/react-scripts-4.0.1 4 years ago
Rawrington 905448a645
Merge branch 'master' into dependabot/npm_and_yarn/react-scripts-4.0.1 4 years ago
dependabot-preview[bot] 07d061e47f
Bump react-scripts from 3.4.0 to 4.0.1 4 years ago
dependabot-preview[bot] c16f24956d
Bump react from 16.12.0 to 16.14.0 4 years ago
Rawrington 594502e21c
Merge pull request #40 from Rawrington/dependabot/npm_and_yarn/elliptic-6.5.3 4 years ago
Rawrington d907aa3765
Merge pull request #44 from Rawrington/dependabot/npm_and_yarn/lodash-4.17.20 4 years ago
Rawrington a65ca22604
Merge pull request #45 from Rawrington/dependabot/npm_and_yarn/http-proxy-1.18.1 4 years ago
Rawrington 58dbcec0a3
Merge pull request #37 from Rawrington/dependabot/npm_and_yarn/websocket-extensions-0.1.4 4 years ago
Rawrington c9d36958f5
Merge pull request #34 from Rawrington/dependabot/npm_and_yarn/acorn-5.7.4 4 years ago
Rawrington ab52c8925f
Merge pull request #33 from Rawrington/dependabot/npm_and_yarn/react-dom-16.13.0 4 years ago
Rawrington ae8a9e9ba8
Merge pull request #41 from Aho-Senpai/patch-1 4 years ago
Rawrington 575f76d0c9
Merge pull request #51 from nonowazu/save-the-bandwidth 4 years ago
Oowazu Nonowazu 4c38abd443 Fix typeo our glorious laeder ay pointd out to me 4 years ago
Oowazu Nonowazu ffe45c9218 Save a ton of bandwidth by using a rudimentary cache 4 years ago
dependabot-preview[bot] ca892ece4b
[Security] Bump http-proxy from 1.18.0 to 1.18.1 5 years ago
dependabot-preview[bot] fb570ff06f
[Security] Bump lodash from 4.17.15 to 4.17.20 5 years ago
Aho-Senpai 96c86be205
Added PvE version of Goka 5 years ago
dependabot-preview[bot] 7db5041536
[Security] Bump elliptic from 6.5.2 to 6.5.3 5 years ago
dependabot-preview[bot] 48dfd02d30
[Security] Bump websocket-extensions from 0.1.3 to 0.1.4 5 years ago
dependabot-preview[bot] 33818fa21b
[Security] Bump acorn from 5.7.3 to 5.7.4 5 years ago
dependabot-preview[bot] c82202df69
Bump react-dom from 16.12.0 to 16.13.0 5 years ago
Rawrington f1f94bafe5
Merge pull request #20 from Rawrington/dependabot/npm_and_yarn/react-16.12.0 5 years ago
Rawrington 070dc5aebb
Merge branch 'master' into dependabot/npm_and_yarn/react-16.12.0 5 years ago
Rawrington 393c96d2b0
Merge pull request #21 from Rawrington/dependabot/npm_and_yarn/react-dom-16.12.0 5 years ago
dependabot-preview[bot] d3816d30e1
Bump react-dom from 16.9.0 to 16.12.0 5 years ago
dependabot-preview[bot] b15e7876ff
Bump react from 16.9.0 to 16.12.0 5 years ago
Rawrington 8f67f9abba
Merge pull request #31 from Rawrington/dependabot/npm_and_yarn/react-scripts-3.4.0 5 years ago
Rawrington 27ef34a7e8
Merge pull request #23 from Makar8000/master 5 years ago
dependabot-preview[bot] 0f517562d0
Bump react-scripts from 3.1.1 to 3.4.0 5 years ago
Makar e7af4b8ebb
Fix Tsubame-gaeshi Skill IDs 5 years ago
Rawrington bc051eb636 Merge branch 'master' of https://github.com/Rawrington/SkillDisplay 5 years ago
Rawrington 94322dc804 5.1 NIN support fuckery I hate SE grumble grumble 5 years ago
Rawrington 17835cfcca
Update README.md 5 years ago
Rawrington c1dda4bacc Uploaded missing file, small refactoring, OverlayPlugin support (hopefully) 6 years ago
Rawrington 0ffdfacafe
Merge pull request #5 from Rawrington/dependabot/npm_and_yarn/react-16.9.0 6 years ago
Rawrington 7c97f7b55b
Merge branch 'master' into dependabot/npm_and_yarn/react-16.9.0 6 years ago
Rawrington 6c40f6bee2
Merge pull request #6 from Rawrington/dependabot/npm_and_yarn/react-dom-16.9.0 6 years ago
Rawrington da9c2c5ea0
Merge branch 'master' into dependabot/npm_and_yarn/react-dom-16.9.0 6 years ago
Rawrington f1a254e926
Merge pull request #8 from Rawrington/dependabot/npm_and_yarn/react-scripts-3.1.1 6 years ago
Rawrington 60a8055a1a
Merge branch 'master' into dependabot/npm_and_yarn/react-scripts-3.1.1 6 years ago
Rawrington c53710670a
Merge pull request #9 from Rawrington/dependabot/npm_and_yarn/eslint-utils-1.4.2 6 years ago
dependabot-preview[bot] c074dea440
[Security] Bump eslint-utils from 1.3.1 to 1.4.2 6 years ago
dependabot-preview[bot] ef9728b509
Bump react-scripts from 3.0.1 to 3.1.1 6 years ago
dependabot-preview[bot] 9cf9a79f19
Bump react-dom from 16.8.6 to 16.9.0 6 years ago
dependabot-preview[bot] 3db04fdf29
Bump react from 16.8.6 to 16.9.0 6 years ago
Rawrington 8437d717cf
Merge pull request #4 from Rawrington/dependabot/npm_and_yarn/lodash.template-4.5.0 6 years ago
dependabot-preview[bot] c33ee9e1e9
[Security] Bump lodash.template from 4.4.0 to 4.5.0 6 years ago
Rawrington a664f07aa0
Merge pull request #3 from Rawrington/dependabot/npm_and_yarn/lodash-4.17.14 6 years ago
dependabot-preview[bot] 1c5249bd4f
[Security] Bump lodash from 4.17.11 to 4.17.14 6 years ago
Rawrington 64bfab91f5 Added rotation handling (beta!) Don't expand them if you don't wish to show them, report any performance issues and such to me 6 years ago
Rawrington 38f3e88f72 updated README.md 6 years ago
Rawrington 8a75b46f51 band-aid fixes for the pull request and hopefully a strange ongoing issue 6 years ago
Rawrington 7895003b44
Merge pull request #1 from Jessidhia/patch-1 6 years ago
Jessica Franco 8a8591cb93
Refactor Action.js 6 years ago
Rawrington 2ceadb90f5 Fixed some oGCD/GCD displaying and cleaned up code. 6 years ago
Rawrington fdeb281d8b fixed auto-attack bugs and other shenanigans 6 years ago
Rawrington 9a3660bb6d haha xd whoops README.md fixed im dumb 6 years ago
Rawrington 59a55d37a8 updated README.md with a preview image 6 years ago
Rawrington 884d50c9c5 updated README.md 6 years ago
  1. 54
      .github/workflows/main.yml
  2. 74
      README.md
  3. BIN
      images/preview.png
  4. 15251
      package-lock.json
  5. 10
      package.json
  6. 42
      src/ACTListener.js
  7. 23
      src/ACTWebsocket.js
  8. 124
      src/Action.js
  9. 223
      src/App.js
  10. 0
      src/Config.js
  11. 33
      src/Rotation.js
  12. 36
      src/css/Action.css
  13. 45
      src/css/App.css
  14. 32
      src/css/Rotation.css
  15. 21
      src/css/index.css
  16. 15
      src/index.js
  17. 135
      src/serviceWorker.js

@ -0,0 +1,54 @@
name: Build & deploy
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: 13.x
- name: Install NPM packages
run: npm ci
- name: Build project
run: npm run build
- name: Upload production-ready build files
uses: actions/upload-artifact@v2
with:
name: production-files
path: ./build
deploy:
name: Deploy
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
steps:
- name: Download artifact
uses: actions/download-artifact@v2
with:
name: production-files
path: ./build
- name: Deploy to gh-pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build

@ -1,68 +1,14 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## SkillDisplay
A simple no-frills ACTWebSocket overlay for showing actions pressed in an overlay window.
## Available Scripts
## Installation
Make sure the 'Using BeforeLogLineRead' box is checked in ACTWebSocket then click the 'Add URL' button to add this URL:
`https://rawrington.github.io/SkillDisplay/`
In the project directory, you can run:
## Troubleshooting
I have only tested and confirmed this working on the QT5.8.0 variant of OverlayProc with ACTWebSocket 1.3.3.9 so if you are having trouble please use these versions.
### `npm start`
If you find any strange bugs, please report to me on here or find me on the ACT FFXIV discord.
Runs the app in the development mode.<br>
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br>
You will also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.<br>
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.<br>
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br>
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
### Analyzing the Bundle Size
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
### Making a Progressive Web App
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
### Advanced Configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
### Deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
### `npm run build` fails to minify
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
## Preview
![preview.png](./images/preview.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

15251
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,11 +1,11 @@
{
"name": "skilldisplay",
"version": "0.1.0",
"version": "0.3.0",
"private": true,
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1"
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.1"
},
"scripts": {
"start": "react-scripts start",
@ -16,7 +16,7 @@
"eslintConfig": {
"extends": "react-app"
},
"homepage": "https://rawrington.github.io/skilldisplay/",
"homepage": "https://rawrington.github.io/SkillDisplay/",
"browserslist": {
"production": [
">0.2%",

@ -0,0 +1,42 @@
const getHost = () => /[?&]HOST_PORT=(wss?:\/\/[^&/]+)/.exec(window.location.search)
export default function listenToACT(callback) {
if (!getHost()) return listenOverlayPlugin(callback)
return listenActWebSocket(callback)
}
function listenActWebSocket(callback) {
const wsUri = `${getHost()[1]}/BeforeLogLineRead` || undefined
const ws = new WebSocket(wsUri)
ws.onerror = () => ws.close()
ws.onclose = () =>
setTimeout(() => {
listenActWebSocket(callback)
}, 1000)
ws.onmessage = function(e, m) {
if (e.data === ".") return ws.send(".")
const obj = JSON.parse(e.data)
if (obj.msgtype === "SendCharName") {
return callback(obj.msg)
} else if (obj.msgtype === "Chat") {
return callback(...obj.msg.split("|"))
}
}
return () => {
ws.close()
}
}
function listenOverlayPlugin(callback) {
const listener = e => {
callback(...e.detail)
}
document.addEventListener("onLogLine", listener)
return () => {
document.removeEventListener("onLogLine", listener)
}
}

@ -1,23 +0,0 @@
export default function listenActWebSocket(callback) {
const url = new URLSearchParams(window.location.search)
const wsUri = `${url.get('HOST_PORT')}BeforeLogLineRead` || undefined
const ws = new WebSocket(wsUri)
ws.onerror = () => listenActWebSocket()
ws.onmessage = function (e, m) { //PING
if (e.data === '.') return ws.send('.') //PONG
const obj = JSON.parse(e.data)
if(obj.msgtype === 'SendCharName')
{
console.log(obj.msg.charID)
console.log(obj.msg.charName)
return callback(obj.msg)
}
else if(obj.msgtype === 'Chat')
{
const code = obj.msg.substring(0, 2) //first 2 numbers POG
if(code === '21' || code === '22') return callback(obj.msg) //NetworkAbility or NetworkAoeAbility
}
}
}

@ -1,45 +1,101 @@
import React from 'react'
import './css/Action.css'
import React from "react"
import "./css/Action.css"
class Action extends React.Component {
state = {
xivapi_data: []
}
const gcdOverrides = new Set([
15997, //standard step
15998, //technical step
15999,
16000,
16001,
16002, //step actions
16003, //standard finish
16004, //technical finish
16191, //single standard finish
16192, //double standard finish (WHY IS IT LIKE THIS)
16193, //single technical finish
16194, //double technical finish
16195, //triple technical finish
16196, //quadruple technical finish
7418, //flamethrower
16484, //kaeshi higanbana
16485, //kaeshi goken
16486, //kaeshi setsugekka
2259, //ten
18805,
2261, //chi
18806,
2263, //jin
18807,
2265, //fuma shurikan
18873,
18874,
18875,
2267, //raiton
18877,
2266, //katon
18876,
2268, //hyoton
18878,
16492, //hyosho ranryu
16471, //goka meykakku
16491, //goka meykakku (16471 is the PvP version, 16491 is the PvE version)
2270, //doton
18880,
2269, //huton
18879,
2271, //suiton
18881,
2272, //rabbit medium
])
constructor(props) {
super(props);
const ogcdOverrides = new Set([
3559, //bard WM
116, //bard AP
114 //bard MB
])
const actionUrl = "https://xivapi.com/Action/"+props.action_id;
const actionMap = new Map()
console.log(actionUrl)
export default function Action({ actionId, additionalClasses }) {
const [apiData, setApiData] = React.useState()
fetch(actionUrl, { mode: 'cors' })
.then(response => response.json())
.then(data => {this.setState({xivapi_data: data})})
}
React.useEffect(() => {
const mapData = actionMap.get(actionId)
if (mapData != null) {
setApiData(mapData)
return
}
let current = true
void (async () => {
const data = await (await fetch(`https://xivapi.com/Action/${actionId}?columns=Icon,Name,ActionCategoryTargetID`, {
mode: "cors"
})).json()
if (current) {
actionMap.set(actionId, data)
setApiData(data)
}
})()
shouldComponentUpdate() {
if (Object.getOwnPropertyNames(this.state.xivapi_data).length === 0) {
return false
return () => {
current = false
}
return true
}
}, [actionId])
isGCD() {
return (this.state.xivapi_data.ActionCategory.ID !== 4)
if (apiData === undefined || !apiData.Icon) {
return null
}
render() {
if(this.state.xivapi_data.Icon) {
const classes = this.isGCD()?'action-icon gcd':'action-icon ogcd'
const img = "https://xivapi.com"+this.state.xivapi_data.Icon
return <img className={classes} src={img} alt='' />
}
else
{
return null
}
}
return (
<img
className={
gcdOverrides.has(actionId) ||
(!ogcdOverrides.has(actionId) && apiData.ActionCategoryTargetID !== 4)
? `gcd ${additionalClasses}`
: `ogcd ${additionalClasses}`
}
src={`https://xivapi.com/${apiData.Icon}`}
alt={apiData.Name || ""}
/>
)
}
export default Action

@ -1,81 +1,150 @@
import React from 'react'
import listenActWebSocket from './ACTWebsocket'
import './css/App.css'
import Action from './Action'
class App extends React.Component {
state = {
me: 0,
actionlist: [],
actionindex: 1
}
constructor(props) {
super(props)
listenActWebSocket(this.handleLogEvent.bind(this))
}
addActionToOverlay(action_id) {
this.setState((state) => {
const actionlist = state.actionlist.concat(action_id);
return {actionlist}
import React from "react"
import listenToACT from "./ACTListener"
import "./css/App.css"
import Action from "./Action"
import RotationContainer from "./Rotation"
import ReactDOM from "react-dom"
const handleCodes = new Set(["00", "01", "02", "21", "22", "33"])
export default function App() {
const [actionList, setActionList] = React.useState([])
const [encounterList, setEncounterList] = React.useState([])
React.useEffect(() => {
let selfId
let lastTimestamp = ""
let lastAction = -1
let currentZone = "Unknown"
let lastKey = 1
let closeFn = listenToACT((...logSplit) => {
const openNewEncounter = () => {
setEncounterList(encounterList => {
if (
encounterList[0] &&
encounterList[0].rotation &&
encounterList[0].rotation.length <= 0
) {
encounterList.shift()
}
encounterList.unshift({
name: currentZone,
rotation: []
})
return encounterList.slice(0, 3)
})
}
if (logSplit.length === 1 && logSplit[0].charID) {
selfId = logSplit[0].charID
openNewEncounter()
return
}
const [
logCode,
logTimestamp,
logParameter1,
logParameter2,
logParameter3
] = logSplit
if (!handleCodes.has(logCode)) return
switch (logCode) {
case "00":
if (logParameter1 === "0038" && logParameter3 === "end")
openNewEncounter()
return
case "01":
currentZone = logParameter2
return
case "02":
selfId = parseInt(logParameter1, 16)
openNewEncounter()
return
case "33":
if (logParameter2 === "40000012" || logParameter2 === "40000010")
openNewEncounter()
return
default:
break
}
if (selfId === undefined) return
if (parseInt(logParameter1, 16) !== selfId) return
const action = parseInt(logParameter3, 16)
if ( //sanity check the tea sis period wig snapped
((action < 9 || action > 30000) && //is not a combat action
(action < 100001 || action > 100300)) || //and is not a crafting action
(logTimestamp === lastTimestamp && action === lastAction) //or this action is a bug/duplicate
)
return
if (Date.now() - Date.parse(lastTimestamp) > 120000) openNewEncounter() //last action > 120s ago
lastTimestamp = logTimestamp
lastAction = action
const key = (lastKey % 256) + 1
lastKey = key
// This is pretty silly but it's the neatest way to handle the updates going
// out at the same time, without finding some way to merge the action lists....
ReactDOM.unstable_batchedUpdates(() => {
setActionList(actionList => actionList.concat({ action, key }))
setEncounterList(encounterList => {
if (!encounterList[0]) {
encounterList[0] = {
name: currentZone,
rotation: []
}
}
encounterList[0].rotation.push(action)
return encounterList
})
})
setTimeout(() => {
setActionList(actionList => actionList.slice(1))
}, 10000)
})
}
handleLogEvent(data) {
if(data.charID) {
this.setState({me: data.charID})
console.log(data.charID)
return
} //the ME data we need
const me = this.state.me
if(me === 0) return //we need data on the character first
let log = data.split('|')
if(parseInt(log[2],16) !== me) return //we only care about our actions
const action = parseInt(log[4],16)
if(action === 7) return //auto-attack
const index = this.state.actionindex
this.addActionToOverlay({index,action})
this.setState((state) => {
const actionindex = (state.actionindex >= 32)?1:state.actionindex+1
return {actionindex}
})
setTimeout(this.purgeAction.bind(this), 10000)
}
purgeAction() {
this.setState((state) => {
const actionlist = state.actionlist.slice(1)
return {actionlist}
})
}
render() {
let actions = []
console.log(this.state.actionlist)
for (const id in this.state.actionlist) {
const action = this.state.actionlist[id]
actions.push(<Action key={action.index} action_id={action.action} />)
return () => {
closeFn()
}
return <div className="actions">{actions}</div>
}
}, [])
return (
<>
<div className="container">
<div className="actions">
{actionList.map(({ action, key }) => (
<Action
key={key}
actionId={action}
additionalClasses="action-move"
/>
))}
</div>
{encounterList.map((encounter, i) => (
<RotationContainer
key={i}
encounterId={i}
name={encounter.name}
actionList={encounter.rotation}
/>
))}
</div>
</>
)
}
export default App;

@ -0,0 +1,33 @@
import React from "react"
import "./css/Rotation.css"
import Action from "./Action"
export default function RotationContainer({ encounterId, name, actionList }) {
const [open, setOpen] = React.useState(false)
return (
<>
<button
className={open ? "rotation-button expanded" : "rotation-button"}
onClick={() => {
setOpen(open => !open)
}}
>
{encounterId === 0 ? "Current Rotation" : name}
</button>
<RotationContents expanded={open} actionList={actionList} />
</>
)
}
function RotationContents({ expanded, actionList }) {
if (!expanded) return null
return (
<div className="rotation-list">
{actionList.map((action, i) => (
<Action key={i} actionId={action} additionalClasses="action-rotation" />
))}
</div>
)
}

@ -1,25 +1,37 @@
.action-icon {
animation-duration: 10s;
animation-name: action-move;
animation-timing-function: linear;
animation-fill-mode: forwards;
position: absolute;
.action-move {
animation-duration: 10s;
animation-name: action-move;
animation-timing-function: linear;
animation-fill-mode: forwards;
position: absolute;
}
.gcd {
width: 3rem;
vertical-align: top;
}
.ogcd {
width: 2rem;
vertical-align: top;
}
.action-rotation.gcd {
margin-left: 1em;
}
.action-rotation.gcd::before {
content: '\25B6'; /* Unicode character for right arrow */
font-size: 13px;
color: rgba(255, 255, 255, 0.5);
}
@keyframes action-move {
from {
transform: translateX(calc(100vw - 3rem));
}
from {
transform: translateX(calc(100vw - 3rem));
}
to {
transform: translateX(-3rem);
}
to {
transform: translateX(-3rem);
}
}

@ -1,17 +1,40 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 16px;
}
html {
height: 100vh;
overflow: hidden;
background-image: none;
background-repeat: no-repeat;
}
.actions {
margin-top: 1em;
padding-top: 1rem;
background: linear-gradient(180deg,
rgba(0,0,0,0) calc(25% - 1px),
rgba(255,255,255,0.5) calc(25%),
rgba(0,0,0,0) calc(25% + 1px),
rgba(0,0,0,0) calc(50% - 1px),
rgba(255,255,255,1) calc(50%),
rgba(0,0,0,0) calc(50% + 1px)
rgba(255,255,255,0.5) calc(50%),
rgba(0,0,0,0) calc(50% + 1px),
rgba(0,0,0,0) calc(75% - 1px),
rgba(255,255,255,0.5) calc(75%),
rgba(0,0,0,0) calc(75% + 1px)
);
height: 3em;
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
height: 3rem;
padding-bottom: 1rem;
background-color: rgba(20, 20, 20, 0.3);
display: inline-block;
}
margin: auto;
.container {
display: flex;
flex-direction: column;
}

@ -0,0 +1,32 @@
.rotation-list {
padding: 0 18px;
background-color: rgba(80, 80, 80, 0.3);
display: block;
}
.rotation-button {
background-color: rgba(100, 100, 100, 0.3);
color: rgba(255, 255, 255, 0.5);
padding: 0.1em;
width: 100vw;
border: none;
outline: none;
transition: 0.4s;
display: block;
}
.rotation-button.expanded, .rotation-button:hover {
background-color: rgba(120, 120, 120, 0.3);
}
.rotation-button:after {
content: '\25BC';
font-size: 13px;
color: rgb(119,119,119);
float: right;
margin-left: 5px;
}
.rotation-button.expanded:after {
content: "\25B2";
}

@ -1,16 +1,15 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 16px;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 16px;
}
html {
margin: 0;
height: 100vh;
overflow: hidden;
background-color: rgba(20, 20, 20, 0.3);
margin: 0;
height: 100vh;
overflow: hidden;
}

@ -1,12 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './css/index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
ReactDOM.render(<App />, document.getElementById('root'))

@ -1,135 +0,0 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
Loading…
Cancel
Save