Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!-- PROJECT LOGO -->
<br />
<p align="center">
<a href="https://github.com/ShaneIsrael/fireshare">
<a href="https://github.com/fireshare-app/fireshare">
<img src="app/client/src/assets/logo.png" alt="Logo" width="120" height="160">
</a>

Expand All @@ -10,17 +10,17 @@
<p align="center">
Share your game clips, videos, or other media via unique links.
<br /><br />
<a href="https://github.com/shaneisrael/fireshare/actions">
<img alt="Docker Build" src="https://github.com/shaneisrael/fireshare/actions/workflows/docker-publish-main.yml/badge.svg" />
<a href="https://github.com/fireshare-app/fireshare/actions">
<img alt="Docker Build" src="https://github.com/fireshare-app/fireshare/actions/workflows/docker-publish-main.yml/badge.svg" />
</a>
<a href="https://hub.docker.com/r/shaneisrael/fireshare">
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/shaneisrael/fireshare?label=docker%20pulls">
</a>
<a href="https://hub.docker.com/r/shaneisrael/fireshare/tags?page=1&ordering=last_updated">
<img alt="GitHub tag (latest SemVer)" src="https://img.shields.io/github/v/tag/shaneisrael/fireshare?label=version">
<img alt="GitHub tag (latest SemVer)" src="https://img.shields.io/github/v/tag/fireshare-app/fireshare?label=version">
</a>
<a href="https://github.com/shaneisrael/fireshare/stargazers">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/shaneisrael/fireshare">
<a href="https://github.com/fireshare-app/fireshare/stargazers">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/fireshare-app/fireshare">
</a>
<br /><br />
<a href="https://www.buymeacoffee.com/shaneisrael">
Expand All @@ -29,7 +29,7 @@
<br /><br />
<a href="https://demo.fireshare.net">Live Demo</a>
&nbsp;&middot;&nbsp;
<a href="https://github.com/ShaneIsrael/fireshare/issues">Report a Bug</a>
<a href="https://github.com/fireshare-app/fireshare/issues">Report a Bug</a>
</p>
</p>

Expand Down Expand Up @@ -267,7 +267,7 @@ See [EnvironmentVariables.md](./docs/EnvironmentVariables.md) for the full list

1. Clone the repo:
```sh
git clone https://github.com/ShaneIsrael/fireshare.git
git clone https://github.com/fireshare-app/fireshare.git
```
2. Start backend services from the project root:
```sh
Expand Down Expand Up @@ -296,7 +296,7 @@ Contributions are welcome. For larger changes, open an issue first to align on s
5. Rebase on latest `develop`
6. Open a pull request to `develop`

For issues and feature requests, visit the [issue tracker](https://github.com/ShaneIsrael/fireshare/issues).
For issues and feature requests, visit the [issue tracker](https://github.com/fireshare-app/fireshare/issues).

**Please DO NOT open a pull request for a feature or addition that was not previously discussed with me. Pull requests that do this will be automatically closed.**

Expand All @@ -316,11 +316,11 @@ See [TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md) for a full guide covering in

If you like the project, consider giving it a star. It helps increase visibility and supports continued development.

<a href="https://www.star-history.com/?repos=shaneisrael%2Ffireshare&type=date&legend=top-left">
<a href="https://www.star-history.com/?repos=fireshare-app%2Ffireshare&type=date&legend=top-left">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=shaneisrael/fireshare&type=date&theme=dark&legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=shaneisrael/fireshare&type=date&legend=top-left" />
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=shaneisrael/fireshare&type=date&legend=top-left" />
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=fireshare-app/fireshare&type=date&theme=dark&legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=fireshare-app/fireshare&type=date&legend=top-left" />
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=fireshare-app/fireshare&type=date&legend=top-left" />
</picture>
</a>

Expand Down
4 changes: 2 additions & 2 deletions app/client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fireshare",
"version": "1.8.1",
"version": "1.8.2",
"private": true,
"dependencies": {
"@emotion/react": "^11.9.0",
Expand Down
24 changes: 22 additions & 2 deletions app/client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Login from './views/Login'
import Watch from './views/Watch'
import ViewImage from './views/ViewImage'
import Dashboard from './views/Dashboard'
import Home from './views/Home'
import NotFound from './views/NotFound'
import Settings from './views/Settings'
import ImageFeed from './views/ImageFeed'
Expand All @@ -22,6 +23,7 @@ import darkTheme from './common/darkTheme'
import { ConfigService } from './services'
import { getSetting, setSetting } from './common/utils'
import AuthWrapper from './components/utils/AuthWrapper'
import LandingRoute from './components/utils/LandingRoute'
import MainNavbar from './components/nav/MainNavbar'
import GlobalDragDropOverlay from './components/utils/GlobalDragDropOverlay'

Expand Down Expand Up @@ -50,16 +52,34 @@ export default function App() {
<Routes>
<Route
path="/"
element={
<LandingRoute>
<AuthWrapper>
<MainNavbar
page="/"
collapsed={!drawerOpen}
searchable
styleToggle
searchPlaceholder="Search title, game, or #tag..."
>
<Dashboard />
</MainNavbar>
</AuthWrapper>
</LandingRoute>
}
/>
<Route
path="/home"
element={
<AuthWrapper>
<MainNavbar
page="/"
page="/home"
collapsed={!drawerOpen}
searchable
styleToggle
searchPlaceholder="Search title, game, or #tag..."
>
<Dashboard />
<Home />
</MainNavbar>
</AuthWrapper>
}
Expand Down
72 changes: 72 additions & 0 deletions app/client/src/common/sidebarPages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// The content pages an administrator can reorder or hide under Settings → Sidebar.
// The account group (My Profile, File Manager, Settings) is deliberately not part
// of this list: whether those appear depends on who is signed in, not on taste.
//
// The order here is the default order. Each entry names the legacy show_* flag
// that used to hide it: installs configured before the ordered list existed
// still carry only those flags, and anything else that reads them keeps working
// because saving writes both.
export const SIDEBAR_PAGES = [
{ key: 'home', href: '/home', title: 'Home', legacyFlag: 'show_home' },
{ key: 'videos', href: '/', title: 'Videos', legacyFlag: 'show_videos' },
{ key: 'images', href: '/images', title: 'Images', legacyFlag: 'show_images' },
{ key: 'games', href: '/games', title: 'Games', legacyFlag: 'show_games' },
{ key: 'tags', href: '/tags', title: 'Tags', legacyFlag: 'show_tags' },
{ key: 'folders', href: '/folders', title: 'Folders', legacyFlag: 'show_folders' },
]

const KNOWN = new Map(SIDEBAR_PAGES.map((p) => [p.key, p]))

// Normalise ui_config into one ordered list with exactly one entry per known
// page: [{ key, enabled }]. With no saved sidebar_pages the order is the
// default and each page is enabled unless its legacy flag says otherwise, so an
// upgrade changes nothing visible. Unknown keys in a saved list are dropped. A
// page missing from a saved list was added in a later release: it is slotted in
// at its default position, enabled, rather than silently vanishing.
export function resolveSidebarPages(uiConfig) {
const config = uiConfig || {}
const saved = Array.isArray(config.sidebar_pages) ? config.sidebar_pages : null
const result = []
const seen = new Set()

if (saved) {
for (const entry of saved) {
const key = typeof entry === 'string' ? entry : entry?.key
if (!KNOWN.has(key) || seen.has(key)) continue
seen.add(key)
result.push({ key, enabled: typeof entry === 'object' ? entry.enabled !== false : true })
}
}

SIDEBAR_PAGES.forEach((page, defaultIndex) => {
if (seen.has(page.key)) return
if (!saved) {
result.push({ key: page.key, enabled: config[page.legacyFlag] !== false })
return
}
const enabledCount = result.filter((p) => p.enabled).length
result.splice(Math.min(defaultIndex, enabledCount), 0, { key: page.key, enabled: true })
})

return result
}

// The ui_config fields that persist an arrangement. The legacy flags are written
// alongside the list so the two can never disagree.
export function sidebarPagesPatch(pages) {
const patch = { sidebar_pages: pages.map(({ key, enabled }) => ({ key, enabled: enabled !== false })) }
for (const page of SIDEBAR_PAGES) {
const entry = pages.find((p) => p.key === page.key)
patch[page.legacyFlag] = entry ? entry.enabled !== false : true
}
return patch
}

// Where "/" should take a visitor: the first page still shown in the sidebar.
// Undefined until the config has been loaded at least once, "/" (the Videos
// page, which lives there) when nothing is left to prefer.
export function landingHref(uiConfig) {
if (!uiConfig) return undefined
const first = resolveSidebarPages(uiConfig).find((p) => p.enabled)
return first ? KNOWN.get(first.key).href : '/'
}
26 changes: 26 additions & 0 deletions app/client/src/components/cards/MasonryImageCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getPublicImageUrl, getImageThumbnailUrl } from '../../common/utils'
import { ImageService } from '../../services'
import DeleteImageModal from '../modal/DeleteImageModal'
import CheckIcon from '@mui/icons-material/Check'
import ImageIcon from '@mui/icons-material/Image'
import TagChip from '../ui/TagChip'
import UploaderMention from '../user/UploaderMention'

Expand All @@ -25,6 +26,8 @@ const MasonryImageCard = ({
selected = false,
onSelect,
hideUploader = false,
// Marks the card as a photo when it sits among videos, as on the Home feed.
showTypeIndicator = false,
}) => {
const [hover, setHover] = React.useState(false)
const [thumbnailHover, setThumbnailHover] = React.useState(false)
Expand Down Expand Up @@ -222,6 +225,29 @@ const MasonryImageCard = ({
)}
</Box>

{showTypeIndicator && (
<Box
sx={{
position: 'absolute',
top: 8,
right: 8,
width: 28,
height: 28,
borderRadius: '6px',
bgcolor: '#000000A6',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
pointerEvents: 'none',
zIndex: 1,
opacity: thumbnailHover ? 0 : 1,
transition: 'opacity 0.2s ease-in-out',
}}
>
<ImageIcon sx={{ fontSize: 18, color: 'rgba(255,255,255,0.85)' }} />
</Box>
)}

{/* Top-right buttons - show on hover */}
<Box
sx={{
Expand Down
35 changes: 24 additions & 11 deletions app/client/src/components/nav/MainNavbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import MuiAppBar from '@mui/material/AppBar'
import { styled } from '@mui/material/styles'

import MenuIcon from '@mui/icons-material/Menu'
import HomeIcon from '@mui/icons-material/Home'
import SearchIcon from '@mui/icons-material/Search'
import CloseIcon from '@mui/icons-material/Close'
import VideoLibraryIcon from '@mui/icons-material/VideoLibrary'
Expand All @@ -39,6 +40,7 @@ import Search from './Search'
import LightTooltip from '../ui/LightTooltip'
import SnackbarAlert from '../alert/SnackbarAlert'
import { getSetting, setSetting } from '../../common/utils'
import { resolveSidebarPages } from '../../common/sidebarPages'
import GameScanStatus from './GameScanStatus'
import TranscodingStatus from './TranscodingStatus'
import FolderSuggestionInline from './FolderSuggestionInline'
Expand All @@ -63,12 +65,16 @@ const DEMO_BANNER_HEIGHT = 34
// drawer toggle that navigation depends on there.
const PAGES_WITHOUT_TOP_BAR = ['/files', '/settings', '/image', '/profile']

// Content pages carry the key that Settings → Sidebar orders and hides them by
// (see common/sidebarPages.js). Entries without a key form the fixed account
// group that always follows them.
const allPages = [
{ title: 'Videos', icon: <VideoLibraryIcon />, href: '/', private: false },
{ title: 'Images', icon: <PhotoLibraryIcon />, href: '/images', private: false },
{ title: 'Games', icon: <SportsEsportsIcon />, href: '/games', private: false },
{ title: 'Tags', icon: <LocalOfferIcon />, href: '/tags', private: false },
{ title: 'Folders', icon: <FolderCopyIcon />, href: '/folders', private: false },
{ key: 'home', title: 'Home', icon: <HomeIcon />, href: '/home', private: false },
{ key: 'videos', title: 'Videos', icon: <VideoLibraryIcon />, href: '/', private: false },
{ key: 'images', title: 'Images', icon: <PhotoLibraryIcon />, href: '/images', private: false },
{ key: 'games', title: 'Games', icon: <SportsEsportsIcon />, href: '/games', private: false },
{ key: 'tags', title: 'Tags', icon: <LocalOfferIcon />, href: '/tags', private: false },
{ key: 'folders', title: 'Folders', icon: <FolderCopyIcon />, href: '/folders', private: false },
// Every /api/admin/files* endpoint checks current_user.admin, so gating this on
// manage_library would advertise a page whose every request answers 403.
{ title: 'File Manager', icon: <FolderOpenIcon />, href: '/files', private: true, adminOnly: true },
Expand Down Expand Up @@ -276,14 +282,21 @@ function MainNavbar({
// to a single entry would drop it for everyone else.
const ACCOUNT_GROUP = ['/profile', '/files', '/settings']

const allowedPages = withProfile.filter((p) => {
// Content pages appear in the order the administrator arranged them under
// Settings → Sidebar, minus any dragged into its inactive zone. The account
// group keeps its fixed place after them.
const sidebarPages = React.useMemo(() => resolveSidebarPages(uiConfig), [uiConfig])
const orderedPages = React.useMemo(() => {
const content = sidebarPages
.filter((entry) => entry.enabled)
.map((entry) => withProfile.find((p) => p.key === entry.key))
.filter(Boolean)
return [...content, ...withProfile.filter((p) => !p.key)]
}, [withProfile, sidebarPages])

const allowedPages = orderedPages.filter((p) => {
if (p.adminOnly && !isAdmin) return false
if (p.perm && !can(p.perm)) return false
if (p.href === '/' && uiConfig.show_videos === false) return false
if (p.href === '/images' && uiConfig.show_images === false) return false
if (p.href === '/games' && uiConfig.show_games === false) return false
if (p.href === '/tags' && uiConfig.show_tags === false) return false
if (p.href === '/folders' && uiConfig.show_folders === false) return false
return true
})

Expand Down
4 changes: 2 additions & 2 deletions app/client/src/components/nav/VersionBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import VolunteerActivismIcon from '@mui/icons-material/VolunteerActivism'
import BugReportIcon from '@mui/icons-material/BugReport'
import NewReleasesIcon from '@mui/icons-material/NewReleases'

const GITHUB_URL = 'https://github.com/ShaneIsrael/fireshare'
const ISSUES_URL = 'https://github.com/ShaneIsrael/fireshare/issues'
const GITHUB_URL = 'https://github.com/fireshare-app/fireshare'
const ISSUES_URL = 'https://github.com/fireshare-app/fireshare/issues'
const COFFEE_URL = 'https://buymeacoffee.com/shaneisrael'

const actionIconSx = {
Expand Down
Loading
Loading