diff options
-rw-r--r-- | vnext/src/App.js | 143 | ||||
-rw-r--r-- | vnext/src/index.css | 93 | ||||
-rw-r--r-- | vnext/src/index.js | 1 | ||||
-rw-r--r-- | vnext/src/ui/Header.js | 63 | ||||
-rw-r--r-- | vnext/webpack.config.js | 22 |
5 files changed, 148 insertions, 174 deletions
diff --git a/vnext/src/App.js b/vnext/src/App.js index 15e29017..fab438bc 100644 --- a/vnext/src/App.js +++ b/vnext/src/App.js @@ -19,6 +19,7 @@ import { useCookies } from 'react-cookie'; import { me, trends } from './api'; import { useVisitor } from './ui/VisitorContext'; +import Avatar from './ui/Avatar'; /** * @@ -91,8 +92,8 @@ export default function App({ footer }) { }, [hash]); useEffect(() => { - const getTrends = async () => { - setAllTrends(await trends()); + const getTrends = async () => { + setAllTrends(await trends()); }; getTrends(); }, []); @@ -111,66 +112,96 @@ export default function App({ footer }) { return ( <> <Header /> - <div id="content_wrapper"> - { - <aside id="sidebar"> - <div id="sidebar_wrapper"> - {visitor.uid > 0 && (<> - <Link to="/?show=my"> - <Icon name="ei-clock" size="s" /> - <span className="desktop">My feed</span> - </Link> - <Link to="/pm"> - <Icon name="ei-envelope" size="s" /> - <span className="desktop">Messages</span> - </Link> + { + <aside id="sidebar"> + <div id="sidebar_wrapper"> + { + <nav id="global"> + {visitor.uid > 0 ? + <> + <div id="ctitle"> + <Avatar user={visitor} /> + </div> + <Link to={{ pathname: '/post' }}> + <Icon name="ei-pencil" size="s" /> + <span className="desktop">Post</span> + </Link> + <Link to="/?show=my"> + <Icon name="ei-clock" size="s" /> + <span className="desktop">My feed</span> + </Link> + <Link to="/pm"> + <Icon name="ei-envelope" size="s" /> + <span className="desktop">Messages</span> + </Link> + <Link to="/settings" rel="nofollow"> + <Icon name="ei-gear" size="s" /> + <span className="desktop">Settings</span> + </Link> + </> : + <Link to={{ pathname: '/login', state: { retpath: window.location.pathname } }}> + <Icon name="ei-user" size="s" /> + <span className="desktop">Login</span> + </Link> + } <Link to="/?show=discuss"> <Icon name="ei-bell" size="s" /> <span className="desktop">Discussions</span> </Link> - <Link to="/settings" rel="nofollow"> - <Icon name="ei-gear" size="s" /> - <span className="desktop">Settings</span> - </Link> - </>)} - <div className="tags desktop"> - <h4>Trends</h4> - { allTrends.map((it, index) => ( - <Fragment key={it.tag}> - {index > 0 && ' '} - <Link to={`/tag/${it.tag}`}>#{it.tag}</Link> - </Fragment> - )) } - </div> - <div id="footer" className="desktop"> - <div id="footer-left">juick.com © 2008-2022 - {footer && (<><br />Sponsors: <span dangerouslySetInnerHTML={{ __html: footer }}></span></>)}</div> - <div id="footer-right"> - · <Link href="/help/contacts" rel="nofollow">Contacts</Link> - · <Link href="/help/tos" rel="nofollow">TOS</Link> - </div> + { + visitor.uid > 0 ? + <Link to={{ pathname: '/' }}> + <Icon name="ei-bell" size="s" /><span className="desktop">Discuss</span> + { + visitor.unreadCount && + <span className="badge">{visitor.unreadCount}</span> + } + </Link> + : + <Link to='/?media=1' rel="nofollow"> + <Icon name="ei-camera" size="s" /> + <span className="desktop">Photos</span> + </Link> + } + </nav> + } + <div className="tags desktop"> + <h4>Trends</h4> + {allTrends.map((it, index) => ( + <Fragment key={it.tag}> + {index > 0 && ' '} + <Link to={`/tag/${it.tag}`}>#{it.tag}</Link> + </Fragment> + ))} + </div> + <div id="footer" className="desktop"> + <div id="footer-left">© 2008-2022, Juick team + {footer && (<><br />Sponsors: <span dangerouslySetInnerHTML={{ __html: footer }}></span></>)}</div> + <div id="footer-right"> + · <Link href="/help/contacts" rel="nofollow">Contacts</Link> + · <Link href="/help/tos" rel="nofollow">TOS</Link> </div> </div> - </aside> - } - <section id="content" ref={contentRef}> - <Routes> - <Route exact path="/" element={<Discussions />} /> - <Route exact path="/home" element={<Home />} /> - <Route exact path="/discover" element={<Discover />} /> - <Route exact path="/settings" element={<Settings onChange={auth} />} /> - <Route exact path="/login" element={<Login onAuth={auth} />} /> - <Route exact path="/post" element={<Post />} /> - <Route exact path="/pm" element={<Contacts />} /> - <Route exact path="/pm/:user" element={<Chat connection={eventSource} />} /> - <Route exact path="/:user/friends" element={<Friends />} /> - <Route exact path="/:user/readers" element={<Readers />} /> - <Route exact path="/:user" element={<Blog />} /> - <Route exact path="/tag/:tag" element={<Tag />} /> - <Route exact path="/:user/:mid" element={<Thread connection={eventSource} />} /> - </Routes> - </section> - </div> + </div> + </aside> + } + <section id="content" ref={contentRef}> + <Routes> + <Route exact path="/" element={<Discussions />} /> + <Route exact path="/home" element={<Home />} /> + <Route exact path="/discover" element={<Discover />} /> + <Route exact path="/settings" element={<Settings onChange={auth} />} /> + <Route exact path="/login" element={<Login onAuth={auth} />} /> + <Route exact path="/post" element={<Post />} /> + <Route exact path="/pm" element={<Contacts />} /> + <Route exact path="/pm/:user" element={<Chat connection={eventSource} />} /> + <Route exact path="/:user/friends" element={<Friends />} /> + <Route exact path="/:user/readers" element={<Readers />} /> + <Route exact path="/:user" element={<Blog />} /> + <Route exact path="/tag/:tag" element={<Tag />} /> + <Route exact path="/:user/:mid" element={<Thread connection={eventSource} />} /> + </Routes> + </section> </> ); } diff --git a/vnext/src/index.css b/vnext/src/index.css index 14810bc2..1d9292a2 100644 --- a/vnext/src/index.css +++ b/vnext/src/index.css @@ -48,7 +48,7 @@ html, body { width: 100%; height: 100%; - overscroll-behavior-y: none; + overscroll-behavior: none; } body { @@ -124,12 +124,21 @@ hr { border: none; } +#app { + display: grid; + grid-template-columns: auto; + grid-template-rows: auto 1fr auto; + grid-template-areas: + "header" + "content" + "footer"; +} + #header { + grid-area: header; background: var(--text-background-color); border-bottom: 1px solid var(--border-color); - z-index: 10; - position: fixed; - width: 100%; + position: sticky; top: 0; } @@ -142,17 +151,16 @@ hr { } #sidebar { - position: fixed; + grid-area: footer; + position: sticky; bottom: 0; - left: 0; - width: 100%; + background: var(--text-background-color); z-index: 10; } #sidebar_wrapper { - display: flex; - flex-direction: row; - justify-content: space-around; + display: inline-block; + width: 100%; } .nav_content { @@ -160,8 +168,7 @@ hr { } #content { - margin-top: 64px !important; - padding-bottom: 64px; + grid-area: content; } .desktop { @@ -190,20 +197,14 @@ hr { } #ctitle { - display: flex; - flex: 1; - white-space: nowrap; - overflow: hidden; -} - -#ctitle a { - border-bottom: 2px solid transparent; - text-overflow: ellipsis; - overflow: hidden; + padding: 24px; } #global { display: flex; + flex-direction: row; + justify-content: space-around; + width: 100%; } .l { @@ -211,13 +212,9 @@ hr { flex-flow: row wrap; } -#global a, -#ctitle a { +#global > a { display: flex; align-items: center; -} - -#global a { color: var(--dimmed-link-color); padding: 14px 16px; } @@ -231,7 +228,7 @@ hr { vertical-align: middle; } -#sidebar_wrapper > a:hover { +#global > a:hover { background-color: var(--background-color); border-top: 2px solid #ff339a; cursor: pointer; @@ -250,15 +247,11 @@ hr { font-weight: 400; } -#global a, -#ctitle a, .l a, .msg-button { border-bottom: 2px solid transparent; } -#global a:hover, -#ctitle a:hover, .l a:hover, .msg-button:hover { background-color: var(--background-color); @@ -763,19 +756,18 @@ blockquote { display: none; } - #content { - width: 640px; - margin-bottom: 12px; - padding-bottom: 12px; + #app { + grid-template-rows: auto 1fr; + grid-template-columns: 300px auto; + grid-template-areas: + "sidebar header header" + "sidebar content content" + "sidebar content content"; } #sidebar { - position: sticky; - padding: 12px; - margin-top: 66px; + grid-area: sidebar; height: 100%; - z-index: auto; - overflow-y: auto; } article, @@ -785,28 +777,23 @@ blockquote { } #sidebar_wrapper { - width: 300px; - overflow-y: auto; - height: 100%; - position: fixed; - flex-direction: column; - justify-content: start; + padding: 12px; + display: inline-block; + position: sticky; + top: 0; } - #sidebar_wrapper a, .l a { border-right: 2px solid transparent; } - #sidebar_wrapper > a:hover { + #global > a:hover { border-top: initial; border-right: 2px solid #ff339a; } - #header_wrapper, - #content_wrapper { - width: 1000px; - margin: 0 auto; + #global { + flex-direction: column; } #content_wrapper { diff --git a/vnext/src/index.js b/vnext/src/index.js index 3c354826..6c557ae7 100644 --- a/vnext/src/index.js +++ b/vnext/src/index.js @@ -3,7 +3,6 @@ import { hydrateRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import { CookiesProvider } from 'react-cookie'; -import './index.css'; import { VisitorProvider } from './ui/VisitorContext'; const Juick = lazy(() => import('./App')); diff --git a/vnext/src/ui/Header.js b/vnext/src/ui/Header.js index db8959ea..4a665605 100644 --- a/vnext/src/ui/Header.js +++ b/vnext/src/ui/Header.js @@ -1,10 +1,9 @@ import { memo, useCallback } from 'react'; import { Link, useNavigate } from 'react-router-dom'; -import Icon from './Icon'; -import { UserLink } from './UserInfo'; import SearchBox from './SearchBox'; import { useVisitor } from './VisitorContext'; +import Avatar from './Avatar'; function Header() { const [visitor] = useVisitor(); @@ -21,60 +20,12 @@ function Header() { return ( <div id="header"> <div id="header_wrapper"> - { - visitor.uid < 0 ? - <> - <div id="logo"><a href="/" /></div> - <nav id="global"> - <a href="/">Loading...</a> - </nav> - </> - : visitor.uid > 0 ? - <UserLink user={visitor} /> - : <div id="logo"> - <Link to="/">Juick</Link> - </div> - } - { - visitor.uid >= 0 && - <> - <div id="search" className="desktop"> - <SearchBox onSearch={searchAll} /> - </div> - <nav id="global"> - {visitor.uid > 0 ? - <Link to={{ pathname: '/' }}> - <Icon name="ei-bell" size="s" /><span className="desktop">Discuss</span> - { - visitor.unreadCount && - <span className="badge">{visitor.unreadCount}</span> - } - </Link> - : - <Link to='/?media=1' rel="nofollow"> - <Icon name="ei-camera" size="s" /> - <span className="desktop">Photos</span> - </Link> - } - <Link to={{ pathname: '/discover' }} rel="nofollow"> - <Icon name="ei-search" size="s" /> - <span className="desktop">Discover</span> - </Link> - - {visitor.uid > 0 ? - <Link to={{ pathname: '/post' }}> - <Icon name="ei-pencil" size="s" /> - <span className="desktop">Post</span> - </Link> - : - <Link to={{ pathname: '/login', state: { retpath: window.location.pathname } }}> - <Icon name="ei-user" size="s" /> - <span className="desktop">Login</span> - </Link> - } - </nav> - </> - } + <div id="logo"> + <Link to="/">Juick</Link> + </div> + <div id="search" className="desktop"> + <SearchBox onSearch={searchAll} /> + </div> </div> </div> ); diff --git a/vnext/webpack.config.js b/vnext/webpack.config.js index cdcf179c..59e65b8d 100644 --- a/vnext/webpack.config.js +++ b/vnext/webpack.config.js @@ -24,6 +24,7 @@ module.exports = (env, argv) => { 'core-js/modules/web.dom-collections.iterator', 'url-polyfill', __dirname + '/src/index.js', + __dirname + '/src/index.css', require.resolve('evil-icons/assets/evil-icons.css') ] }, @@ -48,7 +49,12 @@ module.exports = (env, argv) => { postcssOptions: { plugins: [ 'stylelint', - ['postcss-preset-env', { stage: 0 } ] + [ + 'postcss-preset-env', { + stage: 0, + autoprefixer: { grid: true } + } + ] ] } } @@ -84,7 +90,7 @@ module.exports = (env, argv) => { new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, - }), + }), new MiniCssExtractPlugin({ filename: 'Juick.[contenthash].css' }), @@ -92,12 +98,12 @@ module.exports = (env, argv) => { template: './src/index.html', filename: './index.html' }), - new ESLintPlugin({ - files: 'src', - lintDirtyModulesOnly: true, - failOnWarning: false, - failOnError: true, - fix: false + new ESLintPlugin({ + files: 'src', + lintDirtyModulesOnly: true, + failOnWarning: false, + failOnError: true, + fix: false }), new ErrorOverlayPlugin() ], |