From 1534c33572b4db43879b314dc013621f429df033 Mon Sep 17 00:00:00 2001 From: raduwen Date: Sun, 1 Aug 2021 16:50:13 +0900 Subject: [PATCH 1/4] implements sign-in and sign-out --- .editorconfig | 9 ++ database.rules.json | 4 +- package.json | 8 +- src/components/App.tsx | 20 ++++ src/components/Preview.tsx | 29 ++++++ src/components/admin/SignInForm/index.tsx | 76 +++++++++++++++ src/components/admin/index.tsx | 37 +++++++ src/components/admin/signin.tsx | 47 +++++++++ src/lib/AuthProvider.tsx | 27 +++++ src/lib/firebase.ts | 27 +++++ src/main.tsx | 26 +---- yarn.lock | 114 +++++++++++++++++++++- 12 files changed, 392 insertions(+), 32 deletions(-) create mode 100644 .editorconfig create mode 100644 src/components/App.tsx create mode 100644 src/components/Preview.tsx create mode 100644 src/components/admin/SignInForm/index.tsx create mode 100644 src/components/admin/index.tsx create mode 100644 src/components/admin/signin.tsx create mode 100644 src/lib/AuthProvider.tsx create mode 100644 src/lib/firebase.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..99580d06 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/database.rules.json b/database.rules.json index f8a4fd28..ecdbb39d 100644 --- a/database.rules.json +++ b/database.rules.json @@ -1,6 +1,6 @@ { "rules": { ".read": true, - ".write": false, + ".write": "auth != null" } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 7dc9d34c..d9d3eb9c 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,12 @@ "dependencies": { "firebase": "^8.6.2", "react": "^17.0.2", - "react-dom": "^17.0.2" + "react-dom": "^17.0.2", + "styled-components": "^5.3.0" }, "devDependencies": { + "@firebase/app-types": "^0.6.3", + "@firebase/auth-types": "^0.10.3", "@firebase/database-types": "^0.7.2", "@types/node": "^14.17.1", "@types/react": "^17.0.2", @@ -27,5 +30,8 @@ "typescript": "^4.3.2", "vite": "^2.4.4", "vite-tsconfig-paths": "^3.3.13" + }, + "resolutions": { + "styled-components": "^5" } } diff --git a/src/components/App.tsx b/src/components/App.tsx new file mode 100644 index 00000000..b7a8f7e5 --- /dev/null +++ b/src/components/App.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import '@/global.css'; +import { Preview } from '@/components/Preview' +import { Index as Admin } from '@/components/admin' + +const App = () => { + const params = new URLSearchParams(location.search); + + const mode = params.get('mode') || 'preview'; + + const Component = mode === 'preview' ? Preview : + mode === 'admin' ? Admin : <>; + + return ( + + ); +}; + +export { App }; diff --git a/src/components/Preview.tsx b/src/components/Preview.tsx new file mode 100644 index 00000000..785b359c --- /dev/null +++ b/src/components/Preview.tsx @@ -0,0 +1,29 @@ +import React, { VFC } from 'react'; + +import { TextWidget } from '@/components/TextWidget'; +import { TimeWidget } from '@/components/TimeWidget'; + +const Widgets = { + 'text': TextWidget, + 'time': TimeWidget, +}; + +const Preview: VFC = () => { + const text = `オレオレOBSウィジェットの整理`; + + const widgets = [ + { name: 'text', props: { text: text } }, + { name: 'time', props: { size: 30 } }, + ]; + + return ( +
+ {widgets.map((widget) => { + const Widget = Widgets[widget.name]; + return + })} +
+ ); +}; + +export { Preview }; diff --git a/src/components/admin/SignInForm/index.tsx b/src/components/admin/SignInForm/index.tsx new file mode 100644 index 00000000..b5aca2be --- /dev/null +++ b/src/components/admin/SignInForm/index.tsx @@ -0,0 +1,76 @@ +import React, { VFC, useEffect, useState } from 'react'; +import styled from 'styled-components'; +import { auth } from '@/lib/firebase'; + +const Button = styled.button` + padding: 0.5rem 1rem; + color: #fff; + background-color: #33bbff; + border-radius: 0.25rem; + cursor: pointer; + &:hover { + background-color: #1188dd; + } +`; + +const FormGroup = styled.div` + display: flex; + margin-bottom: 1rem; + width: 480px; + & > label { + width: 20%; + } + & > input { + flex-grow: 1; + } +`; + +const Input = styled.input` + outline: 1px solid #eee; + padding: 0.25rem 0.5rem; +`; + +type SignInFormProps = { + redirectTo: string; +}; + +const SignInForm: VFC = ({ redirectTo }) => { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + + const signin = async (e: React.SyntheticEvent) => { + e.preventDefault(); + try { + await auth.signInWithEmailAndPassword(email, password); + } catch (err) { + alert(err.message); + } + } + + return ( +
+ + + setEmail(e.target.value)} + /> + + + + setPassword(e.target.value)} + /> + +
+ +
+
+ ); +}; + +export { SignInForm }; diff --git a/src/components/admin/index.tsx b/src/components/admin/index.tsx new file mode 100644 index 00000000..7c7b0f56 --- /dev/null +++ b/src/components/admin/index.tsx @@ -0,0 +1,37 @@ +import React, { VFC, useEffect, useState } from 'react'; +import { User } from '@firebase/auth-types'; + +import { AuthProvider } from '@/lib/AuthProvider'; +import { auth } from '@/lib/firebase'; +import { Signin } from "@/components/admin/signin"; + +const Index: VFC = () => { + const [currentUser, setCurrentUser] = useState(null); + + useEffect(() => { + auth.onAuthStateChanged((user) => { + setCurrentUser(user); + }); + }); + + const signout = async () => { + try { + await auth.signOut(); + } catch (err) { + alert(err.message); + } + }; + + return currentUser !== null ? ( + +

Admin

+
{currentUser?.displayName}
+ +
+ ) : ( + + ) + ; +}; + +export { Index }; diff --git a/src/components/admin/signin.tsx b/src/components/admin/signin.tsx new file mode 100644 index 00000000..b80b2b21 --- /dev/null +++ b/src/components/admin/signin.tsx @@ -0,0 +1,47 @@ +import React, { VFC } from 'react'; +import styled from 'styled-components'; + +import { SignInForm } from "@/components/admin/SignInForm"; + +const Wrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + margin: 0; + height: 100vh; + background-color: #444; +`; + +const Container = styled.div` + display: flex; + align-items: center; + flex-direction: column; + margin: 4rem auto; + padding: 2rem; + width: 640px; + max-width: 640px; + height: 320px; + background-color: #fff; + border-radius: 0.25rem; + box-shadow: 0px 0px 0.5rem 0.25rem rgb(0 0 0 / 10%); +`; + +const H1 = styled.div` + margin-bottom: 2rem; + font-size: 2rem; + font-weight: bold; + line-height: 4rem; +`; + +const Signin: VFC = () => { + return ( + + +

Sign In

+ +
+
+ ); +}; + +export { Signin }; diff --git a/src/lib/AuthProvider.tsx b/src/lib/AuthProvider.tsx new file mode 100644 index 00000000..fe08d1c5 --- /dev/null +++ b/src/lib/AuthProvider.tsx @@ -0,0 +1,27 @@ +import { User } from '@firebase/auth-types'; +import React, { FC, createContext, useEffect, useState } from 'react'; +import { auth } from '@/lib/firebase'; + +type AuthContextProps = { + currentUser: User | null | undefined; +}; + +const AuthContext = createContext({ currentUser: undefined }); + +const AuthProvider: FC = ({ children }) => { + const [currentUser, setCurrentUser] = useState(undefined); + + useEffect(() => { + auth.onAuthStateChanged((user) => { + setCurrentUser(user); + }); + }); + + return ( + + {children} + + ); +}; + +export { AuthProvider }; diff --git a/src/lib/firebase.ts b/src/lib/firebase.ts new file mode 100644 index 00000000..6405e565 --- /dev/null +++ b/src/lib/firebase.ts @@ -0,0 +1,27 @@ +import 'firebase/auth'; +import firebase from 'firebase/app'; + +const config = { + apiKey: import.meta.env.VITE_FIREBASE_KEY, + authDomain: import.meta.env.VITE_FIREBASE_DOMAIN, + databaseURL: import.meta.env.VITE_FIREBASE_DATABASE, + projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID, + storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET, + messagingSenderId: import.meta.env.VITE_FIREBASE_SENDER_ID, + appId: import.meta.env.VITE_FIREBASE_APP_ID, +}; + +let auth; +if (firebase.apps.length === 0) { + firebase.initializeApp(config); + auth = firebase.app().auth(); + if (import.meta.env.VITE_FIREBASE_AUTH_EMULATOR_HOST) { + auth.useEmulator( + `http://${import.meta.env.VITE_FIREBASE_AUTH_EMULATOR_HOST}` + ); + } +} + +// TODO: use database emulator + +export { auth }; diff --git a/src/main.tsx b/src/main.tsx index ae29f104..33c3736c 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -2,31 +2,7 @@ import React from 'react'; import { render } from 'react-dom'; import '@/global.css'; -import { TextWidget } from '@/components/TextWidget'; -import { TimeWidget } from '@/components/TimeWidget'; - -const Widgets = { - 'text': TextWidget, - 'time': TimeWidget, -}; - -const App = () => { - const text = `オレオレOBSウィジェットの整理`; - - const widgets = [ - { name: 'text', props: { text: text } }, - { name: 'time', props: { size: 30 } }, - ]; - - return ( -
- {widgets.map((widget) => { - const Widget = Widgets[widget.name]; - return - })} -
- ); -}; +import { App } from '@/components/App'; render( diff --git a/yarn.lock b/yarn.lock index fbd45057..fef1b7f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -53,6 +53,13 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/helper-annotate-as-pure@^7.0.0": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61" + integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA== + dependencies: + "@babel/types" "^7.14.5" + "@babel/helper-compilation-targets@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz#7a99c5d0967911e972fe2c3411f7d5b498498ecf" @@ -93,7 +100,7 @@ dependencies: "@babel/types" "^7.14.5" -"@babel/helper-module-imports@^7.14.5": +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3" integrity sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ== @@ -206,7 +213,7 @@ "@babel/parser" "^7.14.5" "@babel/types" "^7.14.5" -"@babel/traverse@^7.14.5", "@babel/traverse@^7.14.8": +"@babel/traverse@^7.14.5", "@babel/traverse@^7.14.8", "@babel/traverse@^7.4.5": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.8.tgz#c0253f02677c5de1a8ff9df6b0aacbec7da1a8ce" integrity sha512-kexHhzCljJcFNn1KYAQ6A5wxMRzq9ebYpEDV4+WdNyr3i7O44tanbDOR/xjiG2F3sllan+LgwK+7OMk0EmydHg== @@ -243,6 +250,28 @@ enabled "2.0.x" kuler "^2.0.0" +"@emotion/is-prop-valid@^0.8.8": + version "0.8.8" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" + integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== + dependencies: + "@emotion/memoize" "0.7.4" + +"@emotion/memoize@0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" + integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== + +"@emotion/stylis@^0.8.4": + version "0.8.5" + resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" + integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== + +"@emotion/unitless@^0.7.4": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + "@firebase/analytics-types@0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.4.0.tgz#d6716f9fa36a6e340bc0ecfe68af325aa6f60508" @@ -287,6 +316,11 @@ resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.6.2.tgz#8578cb1061a83ced4570188be9e225d54e0f27fb" integrity sha512-2VXvq/K+n8XMdM4L2xy5bYp2ZXMawJXluUIDzUBvMthVR+lhxK4pfFiqr1mmDbv9ydXvEAuFsD+6DpcZuJcSSw== +"@firebase/app-types@^0.6.3": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.6.3.tgz#3f10514786aad846d74cd63cb693556309918f4b" + integrity sha512-/M13DPPati7FQHEQ9Minjk1HGLm/4K4gs9bR4rzLCWJg64yGtVC0zNg9gDpkw9yc2cvol/mNFxqTtd4geGrwdw== + "@firebase/app@0.6.22": version "0.6.22" resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.6.22.tgz#099f51d2c4302d2c99da82994cd176b5a568cfcc" @@ -305,7 +339,7 @@ resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz#5ce13fc1c527ad36f1bb1322c4492680a6cf4964" integrity sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g== -"@firebase/auth-types@0.10.3": +"@firebase/auth-types@0.10.3", "@firebase/auth-types@^0.10.3": version "0.10.3" resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.10.3.tgz#2be7dd93959c8f5304c63e09e98718e103464d8c" integrity sha512-zExrThRqyqGUbXOFrH/sowuh2rRtfKHp9SBVY2vOqKWdCX1Ztn682n9WLtlUDsiYVIbBcwautYWk2HyCGFv0OA== @@ -1002,6 +1036,21 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +"babel-plugin-styled-components@>= 1.12.0": + version "1.13.2" + resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.2.tgz#ebe0e6deff51d7f93fceda1819e9b96aeb88278d" + integrity sha512-Vb1R3d4g+MUfPQPVDMCGjm3cDocJEUTR7Xq7QS95JWWeksN1wdFRYpD2kulDgI3Huuaf1CZd+NK4KQmqUFh5dA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-module-imports" "^7.0.0" + babel-plugin-syntax-jsx "^6.18.0" + lodash "^4.17.11" + +babel-plugin-syntax-jsx@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -1240,6 +1289,11 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== +camelize@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= + caniuse-lite@^1.0.30001219: version "1.0.30001230" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz#8135c57459854b2240b57a4a6786044bdc5a9f71" @@ -1654,6 +1708,20 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= + +css-to-react-native@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" + integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ== + dependencies: + camelize "^1.0.0" + css-color-keywords "^1.0.0" + postcss-value-parser "^4.0.2" + csstype@^3.0.2: version "3.0.8" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" @@ -2669,6 +2737,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hoist-non-react-statics@^3.0.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + home-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/home-dir/-/home-dir-1.0.0.tgz#2917eb44bdc9072ceda942579543847e3017fe4e" @@ -3975,6 +4050,11 @@ portfinder@^1.0.23: debug "^3.1.1" mkdirp "^0.5.5" +postcss-value-parser@^4.0.2: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + postcss@^8.3.6: version "8.3.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" @@ -4183,6 +4263,11 @@ react-dom@^17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" +react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-refresh@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.10.0.tgz#2f536c9660c0b9b1d500684d9e52a65e7404f7e3" @@ -4498,6 +4583,11 @@ setprototypeof@1.2.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -4726,6 +4816,22 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +styled-components@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.0.tgz#e47c3d3e9ddfff539f118a3dd0fd4f8f4fb25727" + integrity sha512-bPJKwZCHjJPf/hwTJl6TbkSZg/3evha+XPEizrZUGb535jLImwDUdjTNxXqjjaASt2M4qO4AVfoHJNe3XB/tpQ== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/traverse" "^7.4.5" + "@emotion/is-prop-valid" "^0.8.8" + "@emotion/stylis" "^0.8.4" + "@emotion/unitless" "^0.7.4" + babel-plugin-styled-components ">= 1.12.0" + css-to-react-native "^3.0.0" + hoist-non-react-statics "^3.0.0" + shallowequal "^1.1.0" + supports-color "^5.5.0" + superstatic@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/superstatic/-/superstatic-7.1.0.tgz#42cc773a0f500fb691841e0533d0b8c31f25997f" @@ -4763,7 +4869,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^5.0.0, supports-color@^5.3.0: +supports-color@^5.0.0, supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== From 54517c2d19000115912f1cdec350feaa7d40b89b Mon Sep 17 00:00:00 2001 From: raduwen Date: Sun, 8 Aug 2021 15:25:50 +0900 Subject: [PATCH 2/4] implements TextWdiget editor --- package.json | 5 +- src/components/App.tsx | 6 +- src/components/Preview.tsx | 28 +-- src/components/TextWidget/editor.tsx | 49 +++++ src/components/TextWidget/index.tsx | 88 +-------- src/components/TextWidget/types.ts | 20 +++ src/components/TextWidget/widget.tsx | 68 +++++++ src/components/admin/index.tsx | 33 +++- src/lib/firebase.ts | 13 +- yarn.lock | 255 ++++++++++++++++++++++++++- 10 files changed, 450 insertions(+), 115 deletions(-) create mode 100644 src/components/TextWidget/editor.tsx create mode 100644 src/components/TextWidget/types.ts create mode 100644 src/components/TextWidget/widget.tsx diff --git a/package.json b/package.json index d9d3eb9c..3bd5da4f 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,11 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", - "serve": "vite preview", - "firebase:emulator:start": "firebase emulators:start" + "serve": "vite preview" }, "dependencies": { + "@material-ui/core": "^4.12.3", + "@react-firebase/database": "^0.3.11", "firebase": "^8.6.2", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/src/components/App.tsx b/src/components/App.tsx index b7a8f7e5..9df8402f 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -3,6 +3,8 @@ import React from 'react'; import '@/global.css'; import { Preview } from '@/components/Preview' import { Index as Admin } from '@/components/admin' +import { FirebaseDatabaseProvider, FirebaseDatabaseNode } from '@react-firebase/database'; +import firebase from '@/lib/firebase'; const App = () => { const params = new URLSearchParams(location.search); @@ -13,7 +15,9 @@ const App = () => { mode === 'admin' ? Admin : <>; return ( - + + + ); }; diff --git a/src/components/Preview.tsx b/src/components/Preview.tsx index 785b359c..0a090b6b 100644 --- a/src/components/Preview.tsx +++ b/src/components/Preview.tsx @@ -1,4 +1,5 @@ import React, { VFC } from 'react'; +import { FirebaseDatabaseNode } from '@react-firebase/database'; import { TextWidget } from '@/components/TextWidget'; import { TimeWidget } from '@/components/TimeWidget'; @@ -9,19 +10,24 @@ const Widgets = { }; const Preview: VFC = () => { - const text = `オレオレOBSウィジェットの整理`; - - const widgets = [ - { name: 'text', props: { text: text } }, - { name: 'time', props: { size: 30 } }, - ]; - return (
- {widgets.map((widget) => { - const Widget = Widgets[widget.name]; - return - })} + + {d => { + const widgets = d.value || {}; + console.log(Object.values(widgets)); + return ( + <> + { + Object.entries(widgets).map(([id, widget]) => { + const Widget = Widgets[widget.name]; + return + }) + } + + ); + }} +
); }; diff --git a/src/components/TextWidget/editor.tsx b/src/components/TextWidget/editor.tsx new file mode 100644 index 00000000..07654ef9 --- /dev/null +++ b/src/components/TextWidget/editor.tsx @@ -0,0 +1,49 @@ +import React, { Component } from 'react'; +import { FirebaseDatabaseMutation } from '@react-firebase/database' +import type { TextWidgetProps } from '@/components/TextWidget/types'; + +type Props = { + id: string; + props: TextWidgetProps; +}; + +class TextWidgetEditor extends Component { + constructor(props) { + super(props); + this.state = this.props.props; + } + + render() { + return ( +
+ + + + {({ runMutation }) => { + return ( + + ); + }} + +
+ ); + } +} + +export { TextWidgetEditor }; diff --git a/src/components/TextWidget/index.tsx b/src/components/TextWidget/index.tsx index 9b53d43e..16de4826 100644 --- a/src/components/TextWidget/index.tsx +++ b/src/components/TextWidget/index.tsx @@ -1,86 +1,2 @@ -import React, { VFC, CSSProperties } from 'react'; - -type Position = { - top?: number; // px - right?: number; // px - bottom?: number; // px - left?: number; // px -} - -type TextWidgetProps = { - text: string; - textColor?: string; - backgroundColor?: string; - edgeWeight?: number; // px - edgeColor?: string; - width?: number; // px - height?: number; // px - padding?: string; // px - position?: Position; -}; - -const calcTextShadow = (weight, color) => { - const edge = [ - `${weight}px ${weight}px 0 ${color}`, - `-${weight}px -${weight}px 0 ${color}`, - `-${weight}px ${weight}px 0 ${color}`, - `${weight}px -${weight}px 0 ${color}`, - `0px ${weight}px 0 ${color}`, - `0-${weight}px 0 ${color}`, - `-${weight}px 0 0 ${color}`, - `${weight}px 0 0 ${color}` - ].join(', '); - return edge; -}; - -const defaultStyle: CSSProperties = { - boxSizing: 'border-box', - whiteSpace: 'pre-wrap', - overflow: 'hidden', - color: 'white', - backgroundColor: 'rgba(0, 0, 0 0.1)', - textShadow: calcTextShadow(1, 'black'), - width: 320, - height: 540, - padding: '4px 8px', - position: 'absolute', -}; - -const TextWidget: VFC = ({ - text, - textColor, - backgroundColor, - edgeWeight, - edgeColor, - width, - height, - padding, - position, -}) => { - const edge = calcTextShadow(edgeWeight || 1, edgeColor || 'black'); - - const style: CSSProperties = { - ...defaultStyle, - width: `${width || 320}px`, - height: `${height | 540}px`, - padding: padding || '4px 8px', - color: textColor || 'white', - textShadow: edge, - backgroundColor: backgroundColor || 'rgba(0, 0, 0, 0.1)', - }; - - if (position?.top || position?.right || position?.bottom || position?.left) { - if (position?.top) style.top = position.top; - if (position?.right) style.right = position.right; - if (position?.bottom) style.bottom = position.bottom; - if (position?.left) style.left = position.left; - } else { - style.right = 0; - } - - console.log(style); - - return
{text}
; -}; - -export { TextWidget } +export { TextWidget } from './widget'; +export { TextWidgetEditor } from './editor'; diff --git a/src/components/TextWidget/types.ts b/src/components/TextWidget/types.ts new file mode 100644 index 00000000..a1f3ab9c --- /dev/null +++ b/src/components/TextWidget/types.ts @@ -0,0 +1,20 @@ +type Position = { + top?: number; // px + right?: number; // px + bottom?: number; // px + left?: number; // px +} + +type TextWidgetProps = { + text: string; + textColor?: string; + backgroundColor?: string; + edgeWeight?: number; // px + edgeColor?: string; + width?: number; // px + height?: number; // px + padding?: string; // px + position?: Position; +}; + +export type { Position, TextWidgetProps }; diff --git a/src/components/TextWidget/widget.tsx b/src/components/TextWidget/widget.tsx new file mode 100644 index 00000000..20d1b621 --- /dev/null +++ b/src/components/TextWidget/widget.tsx @@ -0,0 +1,68 @@ +import React, { VFC, CSSProperties } from 'react'; +import type { TextWidgetProps } from '@/components/TextWidget/types'; + +const calcTextShadow = (weight, color) => { + const edge = [ + `${weight}px ${weight}px 0 ${color}`, + `-${weight}px -${weight}px 0 ${color}`, + `-${weight}px ${weight}px 0 ${color}`, + `${weight}px -${weight}px 0 ${color}`, + `0px ${weight}px 0 ${color}`, + `0-${weight}px 0 ${color}`, + `-${weight}px 0 0 ${color}`, + `${weight}px 0 0 ${color}` + ].join(', '); + return edge; +}; + +const defaultStyle: CSSProperties = { + boxSizing: 'border-box', + whiteSpace: 'pre-wrap', + overflow: 'hidden', + color: 'white', + backgroundColor: 'rgba(0, 0, 0 0.1)', + textShadow: calcTextShadow(1, 'black'), + width: 320, + height: 540, + padding: '4px 8px', + position: 'absolute', +}; + +const TextWidget: VFC = ({ + text, + textColor, + backgroundColor, + edgeWeight, + edgeColor, + width, + height, + padding, + position, +}) => { + const edge = calcTextShadow(edgeWeight || 1, edgeColor || 'black'); + + const style: CSSProperties = { + ...defaultStyle, + width: `${width || 320}px`, + height: `${height | 540}px`, + padding: padding || '4px 8px', + color: textColor || 'white', + textShadow: edge, + backgroundColor: backgroundColor || 'rgba(0, 0, 0, 0.1)', + }; + + if (position?.top || position?.right || position?.bottom || position?.left) { + if (position?.top) style.top = position.top; + if (position?.right) style.right = position.right; + if (position?.bottom) style.bottom = position.bottom; + if (position?.left) style.left = position.left; + } else { + style.right = 0; + } + + console.log(style); + + return
{text}
; +}; + +export { TextWidget } diff --git a/src/components/admin/index.tsx b/src/components/admin/index.tsx index 7c7b0f56..0c9a1b94 100644 --- a/src/components/admin/index.tsx +++ b/src/components/admin/index.tsx @@ -1,9 +1,35 @@ import React, { VFC, useEffect, useState } from 'react'; import { User } from '@firebase/auth-types'; - +import { FirebaseDatabaseNode } from '@react-firebase/database'; import { AuthProvider } from '@/lib/AuthProvider'; import { auth } from '@/lib/firebase'; -import { Signin } from "@/components/admin/signin"; +import { Signin } from '@/components/admin/signin'; +import { TextWidgetEditor } from '@/components/TextWidget'; + +const Editors = { + 'text': TextWidgetEditor, +}; + +const Widgets: VFC = () => { + return ( +
+ + {d => { + return ( + <> + { + Object.entries(d.value || {}).map(([id, widget]) => { + const Editor = Editors[widget.name]; + return + }) + } + + ); + }} + +
+ ); +} const Index: VFC = () => { const [currentUser, setCurrentUser] = useState(null); @@ -23,10 +49,11 @@ const Index: VFC = () => { }; return currentUser !== null ? ( - +

Admin

{currentUser?.displayName}
+
) : ( diff --git a/src/lib/firebase.ts b/src/lib/firebase.ts index 6405e565..a4ac1b7a 100644 --- a/src/lib/firebase.ts +++ b/src/lib/firebase.ts @@ -1,4 +1,5 @@ import 'firebase/auth'; +import 'firebase/database'; import firebase from 'firebase/app'; const config = { @@ -12,16 +13,12 @@ const config = { }; let auth; +let db; if (firebase.apps.length === 0) { firebase.initializeApp(config); auth = firebase.app().auth(); - if (import.meta.env.VITE_FIREBASE_AUTH_EMULATOR_HOST) { - auth.useEmulator( - `http://${import.meta.env.VITE_FIREBASE_AUTH_EMULATOR_HOST}` - ); - } + db = firebase.database(); } -// TODO: use database emulator - -export { auth }; +export default firebase; +export { auth, db }; diff --git a/yarn.lock b/yarn.lock index fef1b7f1..7bc26ed5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -204,6 +204,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446" + integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" @@ -250,6 +257,11 @@ enabled "2.0.x" kuler "^2.0.0" +"@emotion/hash@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + "@emotion/is-prop-valid@^0.8.8": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" @@ -598,6 +610,70 @@ resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== +"@material-ui/core@^4.12.3": + version "4.12.3" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.3.tgz#80d665caf0f1f034e52355c5450c0e38b099d3ca" + integrity sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw== + dependencies: + "@babel/runtime" "^7.4.4" + "@material-ui/styles" "^4.11.4" + "@material-ui/system" "^4.12.1" + "@material-ui/types" "5.1.0" + "@material-ui/utils" "^4.11.2" + "@types/react-transition-group" "^4.2.0" + clsx "^1.0.4" + hoist-non-react-statics "^3.3.2" + popper.js "1.16.1-lts" + prop-types "^15.7.2" + react-is "^16.8.0 || ^17.0.0" + react-transition-group "^4.4.0" + +"@material-ui/styles@^4.11.4": + version "4.11.4" + resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.11.4.tgz#eb9dfccfcc2d208243d986457dff025497afa00d" + integrity sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew== + dependencies: + "@babel/runtime" "^7.4.4" + "@emotion/hash" "^0.8.0" + "@material-ui/types" "5.1.0" + "@material-ui/utils" "^4.11.2" + clsx "^1.0.4" + csstype "^2.5.2" + hoist-non-react-statics "^3.3.2" + jss "^10.5.1" + jss-plugin-camel-case "^10.5.1" + jss-plugin-default-unit "^10.5.1" + jss-plugin-global "^10.5.1" + jss-plugin-nested "^10.5.1" + jss-plugin-props-sort "^10.5.1" + jss-plugin-rule-value-function "^10.5.1" + jss-plugin-vendor-prefixer "^10.5.1" + prop-types "^15.7.2" + +"@material-ui/system@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.1.tgz#2dd96c243f8c0a331b2bb6d46efd7771a399707c" + integrity sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw== + dependencies: + "@babel/runtime" "^7.4.4" + "@material-ui/utils" "^4.11.2" + csstype "^2.5.2" + prop-types "^15.7.2" + +"@material-ui/types@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2" + integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A== + +"@material-ui/utils@^4.11.2": + version "4.11.2" + resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.11.2.tgz#f1aefa7e7dff2ebcb97d31de51aecab1bb57540a" + integrity sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA== + dependencies: + "@babel/runtime" "^7.4.4" + prop-types "^15.7.2" + react-is "^16.8.0 || ^17.0.0" + "@npmcli/move-file@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" @@ -669,6 +745,15 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= +"@react-firebase/database@^0.3.11": + version "0.3.11" + resolved "https://registry.yarnpkg.com/@react-firebase/database/-/database-0.3.11.tgz#6367a249f6cd2d85b51b95c1883254d02c49f509" + integrity sha512-pVOILZwFShciopf/7CC/3rRAWcd1CQ5g0JPkhAWSiMP97fiUiaWtVrnBRtoWVY7kQqyF4G9ZyR/Wm43J9a3ZQA== + dependencies: + immer "^1.5.0" + lodash "^4.17.11" + render-and-add-props "^0.5.0" + "@rollup/pluginutils@^4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.1.tgz#1d4da86dd4eded15656a57d933fda2b9a08d47ec" @@ -748,6 +833,13 @@ dependencies: "@types/react" "*" +"@types/react-transition-group@^4.2.0": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.2.tgz#38890fd9db68bf1f2252b99a942998dc7877c5b3" + integrity sha512-KibDWL6nshuOJ0fu8ll7QnV/LVTo3PzQ9aCPnRUYPfX7eZohHwLIdNHj7pftanREzHNP4/nJa8oeM73uSiavMQ== + dependencies: + "@types/react" "*" + "@types/react@*": version "17.0.8" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.8.tgz#fe76e3ba0fbb5602704110fd1e3035cf394778e3" @@ -1464,6 +1556,11 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= +clsx@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -1722,6 +1819,19 @@ css-to-react-native@^3.0.0: css-color-keywords "^1.0.0" postcss-value-parser "^4.0.2" +css-vendor@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d" + integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ== + dependencies: + "@babel/runtime" "^7.8.3" + is-in-browser "^1.0.2" + +csstype@^2.5.2: + version "2.6.17" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.17.tgz#4cf30eb87e1d1a005d8b6510f95292413f6a1c0e" + integrity sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A== + csstype@^3.0.2: version "3.0.8" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" @@ -1843,6 +1953,14 @@ destroy@^1.0.4, destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + dom-storage@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/dom-storage/-/dom-storage-2.1.0.tgz#00fb868bc9201357ea243c7bcfd3304c1e34ea39" @@ -2737,7 +2855,7 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hoist-non-react-statics@^3.0.0: +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -2814,6 +2932,11 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" +hyphenate-style-name@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" + integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -2838,6 +2961,11 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +immer@^1.5.0: + version "1.12.1" + resolved "https://registry.yarnpkg.com/immer/-/immer-1.12.1.tgz#40c6e5b292c00560836c2993bda3a24379d466f5" + integrity sha512-3fmKM6ovaqDt0CdC9daXpNi5x/YCYS3i4cwLdTVkhJdk5jrDXoPs7lCm3IqM3yhfSnz4tjjxbRG2CziQ7m8ztg== + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -2985,6 +3113,11 @@ is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-in-browser@^1.0.2, is-in-browser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" + integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU= + is-installed-globally@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" @@ -3223,6 +3356,76 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jss-plugin-camel-case@^10.5.1: + version "10.7.1" + resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.7.1.tgz#e7f7097cf97e9deec599cef3275e213452318b93" + integrity sha512-+ioIyWvmAfgDCWXsQcW1NMnLBvRinOVFkSYJUgewQ6TynOcSj5F1bSU23B7z0p1iqK0PPHIU62xY1iNJD33WGA== + dependencies: + "@babel/runtime" "^7.3.1" + hyphenate-style-name "^1.0.3" + jss "10.7.1" + +jss-plugin-default-unit@^10.5.1: + version "10.7.1" + resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.7.1.tgz#826270e2ee38d7024a281ac67c30d6944f124786" + integrity sha512-tW+dfYVNARBQb/ONzBwd8uyImigyzMiAEDai+AbH5rcHg5h3TtqhAkxx06iuZiT/dZUiFdSKlbe3q9jZGAPIwA== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.7.1" + +jss-plugin-global@^10.5.1: + version "10.7.1" + resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.7.1.tgz#9725c46d662aac2e596a0a8741944c060e2b90a1" + integrity sha512-FbxCnu44IkK/bw8X3CwZKmcAnJqjAb9LujlAc/aP0bMSdVa3/MugKQRyeQSu00uGL44feJJDoeXXiHOakBr/Zw== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.7.1" + +jss-plugin-nested@^10.5.1: + version "10.7.1" + resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.7.1.tgz#35563a7a710a45307fd6b9742ffada1d72a62eb7" + integrity sha512-RNbICk7FlYKaJyv9tkMl7s6FFfeLA3ubNIFKvPqaWtADK0KUaPsPXVYBkAu4x1ItgsWx67xvReMrkcKA0jSXfA== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.7.1" + tiny-warning "^1.0.2" + +jss-plugin-props-sort@^10.5.1: + version "10.7.1" + resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.7.1.tgz#1d12b26048541ed3a2ed1b69f7fc231605728362" + integrity sha512-eyd5FhA+J0QrpqXxO7YNF/HMSXXl4pB0EmUdY4vSJI4QG22F59vQ6AHtP6fSwhmBdQ98Qd9gjfO+RMxcE39P1A== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.7.1" + +jss-plugin-rule-value-function@^10.5.1: + version "10.7.1" + resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.7.1.tgz#123eb796eb9982f8efa7a7e362daddd90c0c69fe" + integrity sha512-fGAAImlbaHD3fXAHI3ooX6aRESOl5iBt3LjpVjxs9II5u9tzam7pqFUmgTcrip9VpRqYHn8J3gA7kCtm8xKwHg== + dependencies: + "@babel/runtime" "^7.3.1" + jss "10.7.1" + tiny-warning "^1.0.2" + +jss-plugin-vendor-prefixer@^10.5.1: + version "10.7.1" + resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.7.1.tgz#217821be2d6dacee31d2d464886760ba7742e19a" + integrity sha512-1UHFmBn7hZNsHXTkLLOL8abRl8vi+D1EVzWD4WmLFj55vawHZfnH1oEz6TUf5Y61XHv0smdHabdXds6BgOXe3A== + dependencies: + "@babel/runtime" "^7.3.1" + css-vendor "^2.0.8" + jss "10.7.1" + +jss@10.7.1, jss@^10.5.1: + version "10.7.1" + resolved "https://registry.yarnpkg.com/jss/-/jss-10.7.1.tgz#16d846e1a22fb42e857b99f9c6a0c5a27341c804" + integrity sha512-5QN8JSVZR6cxpZNeGfzIjqPEP+ZJwJJfZbXmeABNdxiExyO+eJJDy6WDtqTf8SDKnbL5kZllEpAP71E/Lt7PXg== + dependencies: + "@babel/runtime" "^7.3.1" + csstype "^3.0.2" + is-in-browser "^1.1.3" + tiny-warning "^1.0.2" + jwa@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" @@ -3454,7 +3657,7 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -loose-envify@^1.1.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -4041,6 +4244,11 @@ picomatch@^2.2.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== +popper.js@1.16.1-lts: + version "1.16.1-lts" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" + integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA== + portfinder@^1.0.23: version "1.0.28" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -4117,6 +4325,15 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" +prop-types@^15.6.2, prop-types@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + protobufjs@^6.10.0, protobufjs@^6.10.2, protobufjs@^6.8.6: version "6.11.2" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b" @@ -4263,16 +4480,31 @@ react-dom@^17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" -react-is@^16.7.0: +react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +"react-is@^16.8.0 || ^17.0.0": + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + react-refresh@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.10.0.tgz#2f536c9660c0b9b1d500684d9e52a65e7404f7e3" integrity sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ== +react-transition-group@^4.4.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" + integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -4356,6 +4588,11 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + registry-auth-token@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" @@ -4370,6 +4607,11 @@ registry-url@^5.0.0: dependencies: rc "^1.2.8" +render-and-add-props@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/render-and-add-props/-/render-and-add-props-0.5.0.tgz#79e35b2251936ec187188322826e56401c2ef70b" + integrity sha512-jIVQsWxGDHwpMcI0d9w6OxF/GCtwL02Lyqk8aGjyF6LyR9GPLY+1ONwPjs6kbQ2d6gTApWk8aprZkBli0tpG/w== + request@^2.87.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" @@ -4816,7 +5058,7 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -styled-components@^5.3.0: +styled-components@^5, styled-components@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.0.tgz#e47c3d3e9ddfff539f118a3dd0fd4f8f4fb25727" integrity sha512-bPJKwZCHjJPf/hwTJl6TbkSZg/3evha+XPEizrZUGb535jLImwDUdjTNxXqjjaASt2M4qO4AVfoHJNe3XB/tpQ== @@ -4966,6 +5208,11 @@ timers-ext@^0.1.5, timers-ext@^0.1.7: es5-ext "~0.10.46" next-tick "1" +tiny-warning@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + tmp@0.0.33, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" From bc5530fa92c2fd6e3a02853fb5892601efe537c3 Mon Sep 17 00:00:00 2001 From: raduwen Date: Sun, 8 Aug 2021 15:49:17 +0900 Subject: [PATCH 3/4] apply styles --- src/components/TextWidget/editor.tsx | 53 ++++++++++++++++------ src/components/admin/SignInForm/index.tsx | 29 ++++-------- src/components/admin/index.tsx | 55 ++++++++++++++++++----- 3 files changed, 93 insertions(+), 44 deletions(-) diff --git a/src/components/TextWidget/editor.tsx b/src/components/TextWidget/editor.tsx index 07654ef9..590675b9 100644 --- a/src/components/TextWidget/editor.tsx +++ b/src/components/TextWidget/editor.tsx @@ -1,4 +1,6 @@ import React, { Component } from 'react'; +import styled from 'styled-components'; +import { TextField, Button, Typography } from '@material-ui/core'; import { FirebaseDatabaseMutation } from '@react-firebase/database' import type { TextWidgetProps } from '@/components/TextWidget/types'; @@ -7,6 +9,18 @@ type Props = { props: TextWidgetProps; }; +const FormGroup = styled.div` + display: flex; + margin-bottom: 1rem; + width: 480px; + & > label { + width: 20%; + } + & > input { + flex-grow: 1; + } +`; + class TextWidgetEditor extends Component { constructor(props) { super(props); @@ -16,28 +30,41 @@ class TextWidgetEditor extends Component { render() { return (
- + - + {({ runMutation }) => { return ( - + + + ); }} diff --git a/src/components/admin/SignInForm/index.tsx b/src/components/admin/SignInForm/index.tsx index b5aca2be..6f0bde5b 100644 --- a/src/components/admin/SignInForm/index.tsx +++ b/src/components/admin/SignInForm/index.tsx @@ -1,18 +1,8 @@ import React, { VFC, useEffect, useState } from 'react'; import styled from 'styled-components'; +import { TextField, Button } from '@material-ui/core'; import { auth } from '@/lib/firebase'; -const Button = styled.button` - padding: 0.5rem 1rem; - color: #fff; - background-color: #33bbff; - border-radius: 0.25rem; - cursor: pointer; - &:hover { - background-color: #1188dd; - } -`; - const FormGroup = styled.div` display: flex; margin-bottom: 1rem; @@ -25,11 +15,6 @@ const FormGroup = styled.div` } `; -const Input = styled.input` - outline: 1px solid #eee; - padding: 0.25rem 0.5rem; -`; - type SignInFormProps = { redirectTo: string; }; @@ -50,22 +35,24 @@ const SignInForm: VFC = ({ redirectTo }) => { return (
- - setEmail(e.target.value)} /> - - setPassword(e.target.value)} />
-
diff --git a/src/components/admin/index.tsx b/src/components/admin/index.tsx index 0c9a1b94..f38d9b51 100644 --- a/src/components/admin/index.tsx +++ b/src/components/admin/index.tsx @@ -1,4 +1,14 @@ import React, { VFC, useEffect, useState } from 'react'; +import { + makeStyles, + CssBaseline, + Container, + Box, + AppBar, + Toolbar, + Typography, + Button +} from '@material-ui/core'; import { User } from '@firebase/auth-types'; import { FirebaseDatabaseNode } from '@react-firebase/database'; import { AuthProvider } from '@/lib/AuthProvider'; @@ -10,6 +20,15 @@ const Editors = { 'text': TextWidgetEditor, }; +const useStyles = makeStyles((theme) => ({ + root: { + flexGrow: 1, + }, + title: { + flexGrow: 1, + }, +})); + const Widgets: VFC = () => { return (
@@ -32,6 +51,7 @@ const Widgets: VFC = () => { } const Index: VFC = () => { + const classes = useStyles(); const [currentUser, setCurrentUser] = useState(null); useEffect(() => { @@ -49,16 +69,31 @@ const Index: VFC = () => { }; return currentUser !== null ? ( - -

Admin

-
{currentUser?.displayName}
- - -
- ) : ( - - ) - ; + + +
+ + + + Admin + + {currentUser.email} + + + + + + + + + +
+
+ ) : ( + + ); }; export { Index }; From d3eebf432cbb2195652687bbe50d4d0f201bea37 Mon Sep 17 00:00:00 2001 From: raduwen Date: Sun, 8 Aug 2021 16:00:33 +0900 Subject: [PATCH 4/4] types --- src/components/App.tsx | 3 +-- src/components/Preview.tsx | 3 ++- src/components/TextWidget/editor.tsx | 3 ++- src/components/admin/index.tsx | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 9df8402f..aab77701 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -11,8 +11,7 @@ const App = () => { const mode = params.get('mode') || 'preview'; - const Component = mode === 'preview' ? Preview : - mode === 'admin' ? Admin : <>; + const Component = mode === 'admin' ? Admin : Preview; return ( diff --git a/src/components/Preview.tsx b/src/components/Preview.tsx index 0a090b6b..13e7fb2a 100644 --- a/src/components/Preview.tsx +++ b/src/components/Preview.tsx @@ -19,7 +19,8 @@ const Preview: VFC = () => { return ( <> { - Object.entries(widgets).map(([id, widget]) => { + Object.keys(widgets).map((id) => { + const widget: any = widgets[id]; const Widget = Widgets[widget.name]; return }) diff --git a/src/components/TextWidget/editor.tsx b/src/components/TextWidget/editor.tsx index 590675b9..4fafadfb 100644 --- a/src/components/TextWidget/editor.tsx +++ b/src/components/TextWidget/editor.tsx @@ -55,9 +55,10 @@ class TextWidgetEditor extends Component { return (