Skip to content

Commit

Permalink
Improved private / public view toggle
Browse files Browse the repository at this point in the history
  • Loading branch information
jordan-dalby committed Nov 26, 2024
1 parent fe18f11 commit 60f5303
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 48 deletions.
27 changes: 2 additions & 25 deletions client/src/components/auth/UserDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,20 @@
import React, { useRef, useState } from 'react';
import { LogOut, User, Globe } from 'lucide-react';
import { LogOut, User } from 'lucide-react';
import { useAuth } from '../../hooks/useAuth';
import { useOutsideClick } from '../../hooks/useOutsideClick';
import { Link, useLocation } from 'react-router-dom';
import { Link } from 'react-router-dom';

export const UserDropdown: React.FC = () => {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
const { user, logout } = useAuth();
const location = useLocation();

if (user?.id === 0) {
return (<></>)
}

useOutsideClick(dropdownRef, () => setIsOpen(false));

const isPublicView = location.pathname.startsWith('/public');
const switchViewProps = isPublicView
? {
to: "/",
icon: <User size={16} />,
text: "My snippets"
}
: {
to: "/public/snippets",
icon: <Globe size={16} />,
text: "Public snippets"
};

if (user) {
return (
<div ref={dropdownRef} className="relative">
Expand All @@ -46,15 +32,6 @@ export const UserDropdown: React.FC = () => {
className="absolute right-0 mt-1 w-48 bg-light-surface dark:bg-dark-surface rounded-md shadow-lg
border border-light-border dark:border-dark-border py-1 z-50"
>
<Link
to={switchViewProps.to}
onClick={() => setIsOpen(false)}
className="w-full px-4 py-2 text-sm text-left text-light-text dark:text-dark-text hover:bg-light-hover
dark:hover:bg-dark-hover flex items-center gap-2"
>
{switchViewProps.icon}
<span>{switchViewProps.text}</span>
</Link>
<button
onClick={() => {
setIsOpen(false);
Expand Down
42 changes: 19 additions & 23 deletions client/src/components/snippets/view/common/StorageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,47 @@
import React, { useState } from 'react';
import { Globe, Lock } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { APP_VERSION } from '../../../../constants/settings';
import ViewSwitch from './ViewSwitch';
import { ROUTES } from '../../../../constants/routes';

interface StorageHeaderProps {
isPublicView: boolean;
}

const StorageHeader: React.FC<StorageHeaderProps> = ({ isPublicView }) => {
const [isTooltipVisible, setIsTooltipVisible] = useState(false);
const navigate = useNavigate();

const tooltipText = isPublicView
? "You're viewing publicly shared snippets. These snippets are read-only and visible to everyone."
: "You're viewing your private snippets. Only you can see and modify these snippets.";

const handleViewToggle = (checked: boolean) => {
navigate(checked ? ROUTES.PUBLIC_SNIPPETS : ROUTES.HOME);
};

return (
<div>
<div className="flex flex-col gap-2">
<h1 className="text-4xl font-bold text-light-text dark:text-dark-text flex items-baseline gap-2">
<img src="/logo512.png" alt="ByteStash Logo" className="w-7 h-7" />
ByteStash
<span className="text-sm text-light-text-secondary dark:text-dark-text-secondary">v{APP_VERSION}</span>
</h1>

<div
className="relative mt-1"
className="relative inline-block"
onMouseEnter={() => setIsTooltipVisible(true)}
onMouseLeave={() => setIsTooltipVisible(false)}
>
<div className="flex items-center gap-1.5">
{isPublicView ? (
<Globe className="w-3.5 h-3.5 text-light-primary dark:text-dark-primary" aria-label="Public View" />
) : (
<Lock className="w-3.5 h-3.5 text-emerald-600 dark:text-emerald-400" aria-label="Private View" />
)}
<span className={`text-sm ${
isPublicView
? 'text-light-primary dark:text-dark-primary'
: 'text-emerald-600 dark:text-emerald-400'
}`}>
{isPublicView ? 'Viewing public snippets' : 'Viewing private snippets'}
</span>
</div>
<ViewSwitch checked={isPublicView} onChange={handleViewToggle} />

{isTooltipVisible && (
<div
className={`absolute left-0 top-full mt-2 w-64 rounded-lg border p-3 text-sm z-50 shadow-lg ${
isPublicView
? 'border-light-primary/20 dark:border-dark-primary/20 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200'
: 'border-emerald-600/20 dark:border-emerald-400/20 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200'
}`}
className="absolute left-1/2 top-full mt-3 w-64 -translate-x-1/2 rounded-lg border border-light-border
dark:border-dark-border bg-light-surface dark:bg-dark-surface p-3 text-sm z-50 shadow-lg
text-light-text dark:text-dark-text before:content-[''] before:absolute before:-top-2 before:left-1/2
before:-translate-x-1/2 before:border-8 before:border-transparent before:border-b-light-surface
dark:before:border-b-dark-surface"
role="tooltip"
>
{tooltipText}
Expand All @@ -56,4 +52,4 @@ const StorageHeader: React.FC<StorageHeaderProps> = ({ isPublicView }) => {
);
};

export default StorageHeader;
export default StorageHeader;
61 changes: 61 additions & 0 deletions client/src/components/snippets/view/common/ViewSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import { Globe, Lock } from 'lucide-react';

interface ViewSwitchProps {
checked: boolean;
onChange: (checked: boolean) => void;
}

const ViewSwitch: React.FC<ViewSwitchProps> = ({ checked, onChange }) => {
return (
<div className="flex items-center gap-3 text-sm text-light-text dark:text-dark-text w-full">
<div
className="flex gap-0.5 rounded-lg bg-light-secondary dark:bg-dark-secondary px-0.5 py-0.5 w-full"
role="group"
>
<button
type="button"
onClick={() => onChange(false)}
className={`
flex items-center justify-center gap-1 px-2 py-0.5 rounded-md transition-all duration-200 flex-1
${!checked
? 'bg-light-hover dark:bg-dark-hover'
: 'hover:bg-light-hover/50 dark:hover:bg-dark-hover/50'
}
`}
>
<Lock
className={`
stroke-[2] transition-colors duration-200
${!checked ? 'text-emerald-500' : 'text-light-text/50 dark:text-dark-text/50'}
`}
size={14}
/>
<span className="text-xs font-medium">Private</span>
</button>
<button
type="button"
onClick={() => onChange(true)}
className={`
flex items-center justify-center gap-1 px-2 py-0.5 rounded-md transition-all duration-200 flex-1
${checked
? 'bg-light-hover dark:bg-dark-hover'
: 'hover:bg-light-hover/50 dark:hover:bg-dark-hover/50'
}
`}
>
<Globe
className={`
stroke-[2] transition-colors duration-200
${checked ? 'text-light-primary dark:text-dark-primary' : 'text-light-text/50 dark:text-dark-text/50'}
`}
size={14}
/>
<span className="text-xs font-medium">Public</span>
</button>
</div>
</div>
);
};

export default ViewSwitch;
36 changes: 36 additions & 0 deletions client/src/components/snippets/view/common/ViewToggleButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { Globe, Lock } from 'lucide-react';
import { Link } from 'react-router-dom';
import { ROUTES } from '../../../../constants/routes';

interface ViewToggleButtonProps {
isPublicView: boolean;
}

const ViewToggleButton: React.FC<ViewToggleButtonProps> = ({ isPublicView }) => {
const toggleProps = isPublicView
? {
to: ROUTES.HOME,
icon: <Lock className="w-4 h-4" />,
text: "Switch to private",
className: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 hover:bg-emerald-500/20"
}
: {
to: ROUTES.PUBLIC_SNIPPETS,
icon: <Globe className="w-4 h-4" />,
text: "Switch to public",
className: "bg-light-primary/10 text-light-primary dark:text-dark-primary hover:bg-light-primary/20"
};

return (
<Link
to={toggleProps.to}
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium transition-colors ${toggleProps.className}`}
>
{toggleProps.icon}
<span>{toggleProps.text}</span>
</Link>
);
};

export default ViewToggleButton;
2 changes: 2 additions & 0 deletions client/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module.exports = {
'light-primary': '#2563eb',
'light-hover': '#cbd5e1',
'light-hover-more': '#eff2f6',
'light-secondary': '#cbd5e1',

'dark-bg': '#0f172a',
'dark-surface': '#1e293b',
Expand All @@ -25,6 +26,7 @@ module.exports = {
'dark-primary': '#2563eb',
'dark-hover': '#334155',
'dark-hover-more': '#4d6280',
'dark-secondary': '#1a2436',
},
},
},
Expand Down

0 comments on commit 60f5303

Please sign in to comment.