Skip to content

Commit

Permalink
feat: Improve accessibility with screen reader support
Browse files Browse the repository at this point in the history
- Added hidden dialog titles for ControlPanel and AuthModal
- Simplified WebGL fingerprinting string generation
- Conditionally render Footer based on workbench visibility
  • Loading branch information
Toddyclipsgg committed Feb 16, 2025
1 parent e808a3d commit 757d306
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 22 deletions.
1 change: 1 addition & 0 deletions app/components/@settings/core/ControlPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ export const ControlPanel = ({ open, onClose }: ControlPanelProps) => {
onPointerDownOutside={onClose}
className="relative z-[101]"
>
<RadixDialog.Title className="sr-only">Settings Panel</RadixDialog.Title>
<motion.div
className={classNames(
'w-[1200px] h-[90vh]',
Expand Down
6 changes: 5 additions & 1 deletion app/components/@settings/tabs/profile/ProfileTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export default function ProfileTab() {
};

const handleProfileUpdate = (field: 'username' | 'bio' | 'email', value: string) => {
if (!auth.isAuthenticated || auth.isGuest) {
return;
}

if (field === 'email' && auth.user) {
// TODO: Implement email change with proper verification
toast.info('Email change requires verification - coming soon');
Expand All @@ -57,7 +61,7 @@ export default function ProfileTab() {
toast.success(`${field.charAt(0).toUpperCase() + field.slice(1)} updated`);
}, 1000);

return () => clearTimeout(debounceToast);
clearTimeout(debounceToast);
};

if (!auth.isAuthenticated || auth.isGuest) {
Expand Down
5 changes: 3 additions & 2 deletions app/components/auth/AuthModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Dialog, DialogContent, DialogOverlay } from '@radix-ui/react-dialog';
import { Dialog, DialogContent, DialogOverlay, DialogTitle } from '@radix-ui/react-dialog';
import { useStore } from '@nanostores/react';
import { authModalStore, updateAuthModal, type AuthModalType } from '~/lib/stores/auth';
import { authModalStore, updateAuthModal } from '~/lib/stores/auth';
import SignInForm from './SignInForm';
import SignUpForm from './SignUpForm';

Expand All @@ -12,6 +12,7 @@ export function AuthModal() {
<Dialog open={isOpen} onOpenChange={(open) => updateAuthModal({ isOpen: open })}>
<DialogOverlay className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50" />
<DialogContent className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[90vw] max-w-md z-50">
<DialogTitle className="sr-only">{isSignIn ? 'Sign In' : 'Sign Up'}</DialogTitle>
<div className="bg-bolt-elements-background-depth-1 rounded-lg p-6 relative">
<button
onClick={() => updateAuthModal({ isOpen: false })}
Expand Down
4 changes: 1 addition & 3 deletions app/components/auth/SignUpForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useStore } from '@nanostores/react';
import { classNames } from '~/utils/classNames';
import { authStore, signUp, updateAuthModal } from '~/lib/stores/auth';
import type { SignUpCredentials } from '~/types/auth';
import { useNavigate } from '@remix-run/react';

interface PasswordValidation {
hasMinLength: boolean;
Expand All @@ -14,8 +13,7 @@ interface PasswordValidation {
}

export default function SignUpForm() {
const { isLoading, error, isGuest } = useStore(authStore);
const navigate = useNavigate();
const { isLoading, error } = useStore(authStore);
const [credentials, setCredentials] = useState<SignUpCredentials>({
email: '',
password: '',
Expand Down
1 change: 0 additions & 1 deletion app/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
isDeviceBlocked,
canCreateNewAccount,
} from './security/deviceFingerprint';
import type { DeviceInfo } from '~/types/security';

export async function signUp(email: string, password: string, username: string) {
try {
Expand Down
20 changes: 6 additions & 14 deletions app/lib/security/deviceFingerprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,9 @@ export async function getDeviceFingerprint(): Promise<DeviceInfo> {
const gl = canvas.getContext('webgl');

if (gl) {
deviceInfo.webgl = [
gl.getParameter(gl.VENDOR),
gl.getParameter(gl.RENDERER),
gl.getParameter(gl.VERSION),
'::'
];
deviceInfo.webgl = [gl.getParameter(gl.VENDOR), gl.getParameter(gl.RENDERER), gl.getParameter(gl.VERSION)].join(
'::',
);
}
} catch (e) {
console.warn('WebGL fingerprinting failed:', e);
Expand Down Expand Up @@ -145,11 +142,8 @@ export function calculateRiskScore(deviceInfo: DeviceInfo, metrics: SecurityMetr
// Função para verificar comportamento incomum
function checkUnusualBehavior(deviceInfo: DeviceInfo): boolean {
// Verifica se o user agent parece ser de um bot
const botPatterns = [
/bot/i, /crawler/i, /spider/i, /headless/i,
/selenium/i, /puppeteer/i, /phantom/i
];

const botPatterns = [/bot/i, /crawler/i, /spider/i, /headless/i, /selenium/i, /puppeteer/i, /phantom/i];

if (botPatterns.some((pattern) => pattern.test(deviceInfo.userAgent))) {
return true;
}
Expand Down Expand Up @@ -193,9 +187,7 @@ export async function updateSecurityMetrics(
updates.blockedUntil = blockUntil.toISOString();
}

const { error } = await supabase
.from('security_metrics')
.upsert(updates);
const { error } = await supabase.from('security_metrics').upsert(updates);

if (error) {
throw error;
Expand Down
5 changes: 4 additions & 1 deletion app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import BackgroundRays from '~/components/ui/BackgroundRays';
import { ControlPanel } from '~/components/@settings';
import { Footer } from '~/components/footer/Footer';
import { useState } from 'react';
import { useStore } from '@nanostores/react';
import { workbenchStore } from '~/lib/stores/workbench';

export const meta: MetaFunction = () => {
return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }];
Expand All @@ -16,6 +18,7 @@ export const loader = () => json({});

export default function Index() {
const [showControlPanel, setShowControlPanel] = useState(false);
const showWorkbench = useStore(workbenchStore.showWorkbench);

return (
<div className="flex flex-col min-h-screen w-full bg-bolt-elements-background-depth-1">
Expand All @@ -24,7 +27,7 @@ export default function Index() {
<main className="flex-1 mb-12">
<ClientOnly fallback={<BaseChat />}>{() => <Chat />}</ClientOnly>
</main>
<Footer />
{!showWorkbench && <Footer />}
<ClientOnly>
{() => <ControlPanel open={showControlPanel} onClose={() => setShowControlPanel(false)} />}
</ClientOnly>
Expand Down

0 comments on commit 757d306

Please sign in to comment.