improve tv support

This commit is contained in:
Cloudburst 2022-08-27 10:45:32 +02:00
parent 006cff303e
commit 711823a824
9 changed files with 126 additions and 51 deletions

View file

@ -1 +1,15 @@
require("prism-themes/themes/prism-dracula.min.css") import { init } from '@noriginmedia/norigin-spatial-navigation';
require("prism-themes/themes/prism-dracula.min.css")
if (window !== undefined) {
init({
visualDebug: false
});
// window.addEventListener("keypress", (evt) => {
// if (evt.keyCode === 461) {
// window.history.go(-1)
// }
// })
}

20
package-lock.json generated
View file

@ -8,6 +8,7 @@
"name": "recloudstream", "name": "recloudstream",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@noriginmedia/norigin-spatial-navigation": "^1.0.5",
"daisyui": "^2.24.0", "daisyui": "^2.24.0",
"gatsby": "^4.21.1", "gatsby": "^4.21.1",
"gatsby-plugin-html-attributes": "^1.0.5", "gatsby-plugin-html-attributes": "^1.0.5",
@ -2917,6 +2918,17 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/@noriginmedia/norigin-spatial-navigation": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@noriginmedia/norigin-spatial-navigation/-/norigin-spatial-navigation-1.0.5.tgz",
"integrity": "sha512-sLdigBBihZUtlexumYRrPkqg8P8SaSp+ZsLDEfDXdySP+/NK+uGCkRl7vi/GboTfDghdKt88KhwOa8sjvTuu5Q==",
"dependencies": {
"lodash": "^4.17.21"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@parcel/bundler-default": { "node_modules/@parcel/bundler-default": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.6.2.tgz", "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.6.2.tgz",
@ -22844,6 +22856,14 @@
"fastq": "^1.6.0" "fastq": "^1.6.0"
} }
}, },
"@noriginmedia/norigin-spatial-navigation": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@noriginmedia/norigin-spatial-navigation/-/norigin-spatial-navigation-1.0.5.tgz",
"integrity": "sha512-sLdigBBihZUtlexumYRrPkqg8P8SaSp+ZsLDEfDXdySP+/NK+uGCkRl7vi/GboTfDghdKt88KhwOa8sjvTuu5Q==",
"requires": {
"lodash": "^4.17.21"
}
},
"@parcel/bundler-default": { "@parcel/bundler-default": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.6.2.tgz", "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.6.2.tgz",

View file

@ -15,6 +15,7 @@
"clean": "gatsby clean" "clean": "gatsby clean"
}, },
"dependencies": { "dependencies": {
"@noriginmedia/norigin-spatial-navigation": "^1.0.5",
"daisyui": "^2.24.0", "daisyui": "^2.24.0",
"gatsby": "^4.21.1", "gatsby": "^4.21.1",
"gatsby-plugin-html-attributes": "^1.0.5", "gatsby-plugin-html-attributes": "^1.0.5",

View file

@ -1,14 +1,9 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect } from "react";
import CompatBtn from "../compatbtn";
const RepoCard = ({ url, isFirst }) => { const RepoCard = ({ url, isFirst }) => {
const [data, setData] = useState(null) const [data, setData] = useState(null)
const firstButton = useRef(null)
useEffect(() => {
if (!isFirst) return;
console.log({firstButton})
firstButton.current?.focus()
}, [firstButton])
useEffect(() => { useEffect(() => {
fetch(url) fetch(url)
@ -30,21 +25,26 @@ const RepoCard = ({ url, isFirst }) => {
</p> </p>
<div className="card-actions justify-end"> <div className="card-actions justify-end">
<div className="btn-group"> <div className="btn-group">
<button ref={firstButton} className="btn btn-primary" onClick={() => { <CompatBtn
window.open(`cloudstreamrepo://${url.replace(/^https?:\/\//, "")}`) autoFocus={isFirst}
}}>Install</button> group={true}
<button className="btn" onClick={() => { className="btn-primary"
if (navigator.clipboard) { href={`cloudstreamrepo://${url.replace(/^https?:\/\//, "")}`}
navigator.clipboard.writeText(url); target="_blank"
} else { >Install</CompatBtn>
var tempInput = document.createElement("input"); <CompatBtn group={true}
tempInput.value = url; onClick={() => {
document.body.appendChild(tempInput); if (navigator.clipboard) {
tempInput.select(); navigator.clipboard.writeText(url);
document.execCommand("copy"); } else {
document.body.removeChild(tempInput); var tempInput = document.createElement("input");
} tempInput.value = url;
}}>Copy URL</button> document.body.appendChild(tempInput);
tempInput.select();
document.execCommand("copy");
document.body.removeChild(tempInput);
}
}}>Copy URL</CompatBtn>
</div> </div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,47 @@
import React, { useEffect } from "react";
import { useFocusable } from '@noriginmedia/norigin-spatial-navigation';
import { Link, navigate } from "gatsby";
function CompatBtn({autoFocus, href, onClick, group, target, children, className, ...props}) {
const { ref, focused, focusSelf} = useFocusable();
useEffect(() => {
if (!autoFocus) return;
focusSelf()
}, [focusSelf])
if (onClick) href = "#!"
if (focused && ref.current) {
ref.current?.focus()
}
if (window) {
window.addEventListener("keyup", (ev) => {
if (!focused) return;
if (document.activeElement !== ref.current) return;
if (ev.key === "Enter" || ev.key === " ") {
ref.current?.click()
}
})
}
if (target !== "_blank" && !group && !onClick) {
return <Link to={href} className={`btn ${className||""}`} ref={ref} {...props}>{children}</Link>
} else if (!group && !onClick) {
return <a href={href} target="_blank" className={`btn ${className||""}`} ref={ref} {...props}>{children}</a>
} else {
return <button className={`btn ${className||""}`} ref={ref} {...props} onClick={() => {
if (onClick) {
onClick()
} else if (target === "_blank") {
window.open(href)
} else {
navigate(href)
}
}}>{children}</button>
}
}
export default CompatBtn

View file

@ -1,11 +1,12 @@
import React from "react" import React from "react"
import { Link } from "gatsby"
const Button = ({url, children, name}) => ( const Button = ({url, children, name}) => (
<span className="tooltip tooltip-bottom before:text-xs before:content-[attr(data-tip)]" data-tip={name}> <span className="tooltip tooltip-bottom before:text-xs before:content-[attr(data-tip)]" data-tip={name}>
<div className="flex-none items-center"> <div className="flex-none items-center">
<a className="btn btn-ghost drawer-button btn-square text-xl" href={url || "#!"}> <Link className="btn btn-ghost drawer-button btn-square text-xl" to={url || "#!"}>
{children} {children}
</a> </Link>
</div> </div>
</span> </span>
) )

View file

@ -1,24 +1,18 @@
import React, {useRef, useEffect} from "react" import React from "react"
import Layout from "../components/layout" import Layout from "../components/layout"
import Hero from "../components/hero" import Hero from "../components/hero"
import bgImage from "../media/phones.png" import bgImage from "../media/phones.png"
import { Link } from "gatsby" import CompatBtn from "../components/compatbtn"
const NotFoundPage = () => { const NotFoundPage = () => {
const firstBtn = useRef(null)
useEffect(() => {
firstBtn.current.focus()
}, [firstBtn])
return ( return (
<Layout> <Layout>
<Hero bg={bgImage}> <Hero bg={bgImage}>
<h1 className="mb-5 text-5xl font-bold">Not found</h1> <h1 className="mb-5 text-5xl font-bold">Not found</h1>
<p className="mb-5 text-lg">Sorry 😔. We couldnt find what you were looking for.</p> <p className="mb-5 text-lg">Sorry 😔. We couldnt find what you were looking for.</p>
<Link ref={firstBtn} className="btn btn-primary" to="/">Home</Link> <CompatBtn autoFocus={true} className="btn-primary" href="/">Home</CompatBtn>
</Hero> </Hero>
</Layout> </Layout>
) )

View file

@ -1,26 +1,21 @@
import React, {useEffect, useRef} from "react" import React from "react"
import Layout from "../components/layout" import Layout from "../components/layout"
import Hero from "../components/hero" import Hero from "../components/hero"
import CompatBtn from "../components/compatbtn"
import bgImage from "../media/phones.png" import bgImage from "../media/phones.png"
import { Link } from "gatsby" import { Link } from "gatsby"
const IndexPage = () => { const IndexPage = () => {
const firstBtn = useRef(null)
useEffect(() => {
firstBtn.current.focus()
}, [firstBtn])
return <Layout> return <Layout>
<Hero bg={bgImage}> <Hero bg={bgImage}>
<h1 className="mb-5 text-5xl font-bold">Hello there</h1> <h1 className="mb-5 text-5xl font-bold">Hello there</h1>
<p className="mb-5 text-lg">Cloudstream is an Android app for streaming and downloading Movies, TV-Series and Anime.</p> <p className="mb-5 text-lg">Cloudstream is an Android app for streaming and downloading Movies, TV-Series and Anime.</p>
<div className="flex justify-center w-full mb-5"> <div className="flex justify-center w-full mb-5">
<Link ref={firstBtn} className="btn btn-primary" to="/install">Install</Link> <CompatBtn autoFocus={true} className="btn-primary" href="/install">Install</CompatBtn>
<div className="divider divider-horizontal" /> <div className="divider divider-horizontal" />
<Link className="btn btn-primary" to="/repos">Repositories</Link> <CompatBtn className="btn-primary" href="/repos">Repositories</CompatBtn>
</div> </div>
<Link to="/docs" className="link">Documentation</Link> <Link to="/docs" className="link">Documentation</Link>
</Hero> </Hero>

View file

@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react"
import Layout from "../components/layout" import Layout from "../components/layout"
import Hero from "../components/hero" import Hero from "../components/hero"
import CompatBtn from "../components/compatbtn"
import bgImage from "../media/phones.png" import bgImage from "../media/phones.png"
@ -54,14 +55,16 @@ const InstallPage = () => {
<h1 className="mb-5 text-5xl font-bold">Installation</h1> <h1 className="mb-5 text-5xl font-bold">Installation</h1>
{(data != null) && {(data != null) &&
<div className="flex flex-col items-center gap-3">{ <div className="flex flex-col items-center gap-3">{
data.btns.map(it => { data.btns.map((it, idx) => {
return <div className="btn-group" key={JSON.stringify(it)}> return <div className="btn-group" key={JSON.stringify(it)}>
<button className={"btn " + (it.pre?'btn-secondary':'btn-primary')} onClick={() => { <CompatBtn group={true} autoFocus={idx === 0}
window.open(it.apk.browser_download_url) className={it.pre?'btn-secondary':'btn-primary'}
}}>Download {it.tag}</button> href={it.apk.browser_download_url}
<button className="btn"onClick={() => { target="_blank">Download {it.tag}</CompatBtn>
window.open(it.url) <CompatBtn
}}>Release notes</button> group={true}
href={it.url}
target="_blank">Release notes</CompatBtn>
</div> </div>
})} })}
</div> </div>