diff --git a/web/index.html b/web/index.html
index 4204e87..32e9628 100644
--- a/web/index.html
+++ b/web/index.html
@@ -3,10 +3,10 @@
- StrafesNET Dev Portal
+ StrafesNET | Developer Portal
-
+
diff --git a/web/src/components/Header.tsx b/web/src/components/Header.tsx
index e468fae..c0de433 100644
--- a/web/src/components/Header.tsx
+++ b/web/src/components/Header.tsx
@@ -67,18 +67,32 @@ const Header: React.FC = ({ user, onCreateAppClick, isAdmin, adminV
<>
-
- StrafesNET Developer Portal
-
+
+
+ StrafesNET
+
+
+ Developer Portal
+
+
{/* Rate Limit Display */}
{!adminView && (
diff --git a/web/src/components/RateLimitDisplay.tsx b/web/src/components/RateLimitDisplay.tsx
index 0426798..adba140 100644
--- a/web/src/components/RateLimitDisplay.tsx
+++ b/web/src/components/RateLimitDisplay.tsx
@@ -16,6 +16,7 @@ import {
Refresh as RefreshIcon
} from '@mui/icons-material';
import {RateLimit, RateLimitStatus} from '../types';
+import { primary, border, fill, surface } from '../theme/colors';
interface RateLimitDisplayProps {
rateLimit: RateLimit;
@@ -158,14 +159,15 @@ const RateLimitDisplay: React.FC = ({ rateLimit, rateLimi
componentsProps={{
tooltip: {
sx: {
- bgcolor: 'background.paper',
+ bgcolor: surface.raisedSolid,
color: 'text.primary',
+ border: `1px solid ${border.default}`,
'& .MuiTooltip-arrow': {
- color: 'background.paper',
+ color: surface.raisedSolid,
},
- boxShadow: '0 2px 10px rgba(0, 0, 0, 0.2)',
- borderRadius: 1,
- p: 0, // Remove padding from tooltip to prevent double padding
+ boxShadow: '0 8px 32px rgba(0, 0, 0, 0.4)',
+ borderRadius: 2,
+ p: 0,
}
}
}}
@@ -176,16 +178,16 @@ const RateLimitDisplay: React.FC = ({ rateLimit, rateLimi
alignItems: 'center',
px: 1.5,
py: 0.75,
- mr: 2,
borderRadius: 2,
- backgroundColor: 'rgba(149, 128, 255, 0.15)',
- border: '1px solid rgba(149, 128, 255, 0.3)',
- color: 'primary.main',
+ backgroundColor: fill.primaryStrong,
+ border: `1px solid ${border.primaryStrong}`,
+ color: primary.main,
cursor: 'pointer',
+ transition: 'all 0.15s ease',
'&:hover': {
- backgroundColor: 'rgba(149, 128, 255, 0.25)',
+ backgroundColor: fill.primaryActive,
+ borderColor: primary.main,
},
- transition: 'background-color 0.2s',
}}
>
diff --git a/web/src/components/admin/AdminPage.tsx b/web/src/components/admin/AdminPage.tsx
index ce250f0..f8fa794 100644
--- a/web/src/components/admin/AdminPage.tsx
+++ b/web/src/components/admin/AdminPage.tsx
@@ -15,6 +15,7 @@ import {
import { RateLimit, Permission } from '../../types';
import { adminService } from '../../services/adminService';
import { useNotification } from '../../context/NotificationContext';
+import { text } from '../../theme/colors';
import UsersTab from './users/UsersTab';
import PermissionsTab from './permissions/PermissionsTab';
import RateLimitsTab from './rate-limits/RateLimitsTab';
@@ -53,16 +54,19 @@ const AdminPage: React.FC = () => {
maxWidth="xl"
sx={{ mt: 4, mb: 4, flexGrow: 1, width: '100%', maxWidth: '100% !important' }}
>
-
- Admin Panel
-
+
+
+ Admin Panel
+
+
Manage users, permissions, and rate limit classes.
diff --git a/web/src/components/admin/users/UserDetailDialog.tsx b/web/src/components/admin/users/UserDetailDialog.tsx
index abab8d2..87a029a 100644
--- a/web/src/components/admin/users/UserDetailDialog.tsx
+++ b/web/src/components/admin/users/UserDetailDialog.tsx
@@ -37,6 +37,7 @@ import {
import { AdminUser, RateLimit, Permission, Application } from '../../../types';
import { adminService } from '../../../services/adminService';
import { useNotification } from '../../../context/NotificationContext';
+import { border, fill } from '../../../theme/colors';
interface UserDetailDialogProps {
open: boolean;
@@ -310,16 +311,14 @@ const UserDetailDialog: React.FC = ({
key={service}
sx={{
mb: 2,
- border: '1px solid rgba(255, 255, 255, 0.12)',
- borderRadius: '4px',
'&:before': { display: 'none' },
}}
>
}
sx={{
- borderBottom: '1px solid rgba(255, 255, 255, 0.12)',
- backgroundColor: 'rgba(255, 255, 255, 0.03)',
+ borderBottom: `1px solid ${border.default}`,
+ backgroundColor: fill.subtle,
}}
>
@@ -342,12 +341,13 @@ const UserDetailDialog: React.FC = ({
variant="outlined"
sx={{
p: 1,
- backgroundColor: 'rgba(255, 255, 255, 0.03)',
- borderColor: 'rgba(255, 255, 255, 0.12)',
+ backgroundColor: fill.subtle,
+ borderColor: border.default,
opacity: toggling ? 0.6 : 1,
- transition: 'opacity 0.15s',
+ transition: 'opacity 0.15s, border-color 0.15s',
'&:hover': {
- backgroundColor: 'rgba(255, 255, 255, 0.05)',
+ backgroundColor: fill.primaryHover,
+ borderColor: border.primaryDefault,
},
}}
>
diff --git a/web/src/components/applications/ApplicationCard.tsx b/web/src/components/applications/ApplicationCard.tsx
index 8bca4a3..b0c40ee 100644
--- a/web/src/components/applications/ApplicationCard.tsx
+++ b/web/src/components/applications/ApplicationCard.tsx
@@ -19,6 +19,7 @@ import {
} from '@mui/icons-material';
import { Application, Permission } from '../../types';
import { useApplications } from '../../context/ApplicationContext';
+import { primary, secondary, border, fill, text } from '../../theme/colors';
interface ApplicationCardProps {
app: Application;
@@ -32,42 +33,48 @@ const ApplicationCard: React.FC = ({ app, permissions }) =
const totalAvailablePermissions = permissions.length;
return (
-
+
-
+
{app.name}
handleMenuOpen(e, app.id)}
- sx={{ ml: 'auto' }}
+ sx={{
+ ml: 'auto',
+ color: text.muted,
+ '&:hover': { color: text.secondary, backgroundColor: fill.hover },
+ }}
>
-
+
{app.description || 'No description provided'}
-
-
- Permissions:
+
+
+
+ Permissions
+
0 ? "primary" : "default"}
- sx={{ ml: 1 }}
+ sx={{
+ ml: 1,
+ height: 18,
+ fontSize: '0.7rem',
+ backgroundColor: usedPermissionCount > 0 ? fill.primaryStrong : fill.subtle,
+ color: usedPermissionCount > 0 ? primary.light : text.muted,
+ border: `1px solid ${usedPermissionCount > 0 ? border.primaryMedium : border.default}`,
+ }}
/>
-
+
{appPermissions.reduce((services: string[], permission: Permission) => {
@@ -85,57 +92,74 @@ const ApplicationCard: React.FC = ({ app, permissions }) =
);
})}
+ {appPermissions.length === 0 && (
+
+ No permissions granted
+
+ )}
-
-
- Created: {new Date(app.created_at).toLocaleDateString(undefined, {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- hour: '2-digit',
- minute: '2-digit',
- second: '2-digit'
- })}
+
+ {new Date(app.created_at).toLocaleDateString(undefined, {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ })}
-
+
}
+ startIcon={}
onClick={() => openEditDialog(app)}
- color="primary"
- variant="text"
+ sx={{
+ color: primary.main,
+ fontSize: '0.8rem',
+ '&:hover': { backgroundColor: fill.primaryActive },
+ }}
>
Edit
}
+ startIcon={}
onClick={() => regenerateApiKey(app)}
- color="secondary"
- variant="text"
+ sx={{
+ color: secondary.main,
+ fontSize: '0.8rem',
+ '&:hover': { backgroundColor: 'rgba(34, 211, 238, 0.08)' },
+ }}
>
New Key
@@ -144,4 +168,4 @@ const ApplicationCard: React.FC = ({ app, permissions }) =
);
};
-export default ApplicationCard;
\ No newline at end of file
+export default ApplicationCard;
diff --git a/web/src/components/applications/ApplicationMenu.tsx b/web/src/components/applications/ApplicationMenu.tsx
index 702c92d..31f1eee 100644
--- a/web/src/components/applications/ApplicationMenu.tsx
+++ b/web/src/components/applications/ApplicationMenu.tsx
@@ -6,6 +6,7 @@ import {
VpnKey as VpnKeyIcon
} from '@mui/icons-material';
import { useApplications } from '../../context/ApplicationContext';
+import { fill, text } from '../../theme/colors';
interface ApplicationMenuProps {
anchorEl: HTMLElement | null;
@@ -26,29 +27,19 @@ const ApplicationMenu: React.FC = ({ anchorEl, appId, onCl
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={onClose}
- PaperProps={{
- elevation: 0,
- sx: {
- overflow: 'visible',
- filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
- mt: 1.5,
- '& .MuiAvatar-root': {
- width: 32,
- height: 32,
- ml: -0.5,
- mr: 1,
- },
- '&:before': {
- content: '""',
- display: 'block',
- position: 'absolute',
- top: 0,
- right: 14,
- width: 10,
- height: 10,
- bgcolor: 'background.paper',
- transform: 'translateY(-50%) rotate(45deg)',
- zIndex: 0,
+ slotProps={{
+ paper: {
+ elevation: 0,
+ sx: {
+ mt: 1,
+ minWidth: 180,
+ boxShadow: '0 8px 32px rgba(0, 0, 0, 0.4)',
+ '& .MuiMenuItem-root': {
+ fontSize: '0.875rem',
+ color: text.secondary,
+ transition: 'all 0.15s ease',
+ '&:hover': { backgroundColor: fill.hover, color: text.primary },
+ },
},
},
}}
diff --git a/web/src/components/applications/ApplicationsPage.tsx b/web/src/components/applications/ApplicationsPage.tsx
index 7759d55..51012cf 100644
--- a/web/src/components/applications/ApplicationsPage.tsx
+++ b/web/src/components/applications/ApplicationsPage.tsx
@@ -3,7 +3,6 @@ import {
Container,
Box,
Typography,
- Paper,
Button
} from '@mui/material';
import {
@@ -13,6 +12,7 @@ import {
import ApplicationCard from './ApplicationCard.tsx';
import { Permission, UserInfo } from '../../types';
import { useApplications } from '../../context/ApplicationContext';
+import { primary, text, border, fill } from '../../theme/colors';
interface ApplicationsPageProps {
user: UserInfo;
@@ -26,52 +26,67 @@ const ApplicationsPage: React.FC = ({ user, permissions }
} = useApplications();
return (
-
+
-
+
Your Applications
-
- Create and manage your applications
+
+ Create and manage your API applications
{applications.length === 0 ? (
-
-
-
+
+
+
+
No applications yet
+
+ Create your first app to get an API key
+
}
onClick={openCreateDialog}
disabled={!user.active}
- sx={{ mt: 2 }}
>
Create Your First App
-
+
) : (
= ({ user, permissions }
);
};
-export default ApplicationsPage;
\ No newline at end of file
+export default ApplicationsPage;
diff --git a/web/src/components/applications/dialog/ApiKeyDialog.tsx b/web/src/components/applications/dialog/ApiKeyDialog.tsx
index 04093fc..1de792e 100644
--- a/web/src/components/applications/dialog/ApiKeyDialog.tsx
+++ b/web/src/components/applications/dialog/ApiKeyDialog.tsx
@@ -11,6 +11,7 @@ import {
Tooltip
} from '@mui/material';
import { ContentCopy as ContentCopyIcon } from '@mui/icons-material';
+import { secondary, border, fill } from '../../../theme/colors';
interface ApiKeyDialogProps {
open: boolean;
@@ -43,11 +44,11 @@ const ApiKeyDialog: React.FC = ({
sx={{
p: 2,
mt: 2,
- bgcolor: 'rgba(255, 255, 255, 0.04)',
+ backgroundColor: fill.subtle,
+ borderColor: border.primaryDefault,
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
- border: '1px solid rgba(255, 255, 255, 0.15)',
}}
>
= ({
width: '100%',
overflow: 'auto',
p: 1,
- color: '#80ffea', // Match secondary color for monospace text
+ color: secondary.main,
}}
>
{apiKey}
diff --git a/web/src/components/applications/dialog/ApplicationFormDialog.tsx b/web/src/components/applications/dialog/ApplicationFormDialog.tsx
index 1d4607f..fa1722e 100644
--- a/web/src/components/applications/dialog/ApplicationFormDialog.tsx
+++ b/web/src/components/applications/dialog/ApplicationFormDialog.tsx
@@ -25,6 +25,7 @@ import {
} from '@mui/icons-material';
import { Application, Permission } from '../../../types';
import { useApplications } from '../../../context/ApplicationContext';
+import { border, fill } from '../../../theme/colors';
interface ApplicationFormDialogProps {
open: boolean;
@@ -210,16 +211,14 @@ const ApplicationFormDialog: React.FC = ({
key={service.name}
sx={{
mb: 2,
- border: '1px solid rgba(255, 255, 255, 0.12)',
- borderRadius: '4px',
'&:before': { display: 'none' },
}}
>
}
sx={{
- borderBottom: '1px solid rgba(255, 255, 255, 0.12)',
- backgroundColor: 'rgba(255, 255, 255, 0.03)',
+ borderBottom: `1px solid ${border.default}`,
+ backgroundColor: fill.subtle,
}}
>
@@ -240,10 +239,12 @@ const ApplicationFormDialog: React.FC = ({
variant="outlined"
sx={{
p: 1,
- backgroundColor: 'rgba(255, 255, 255, 0.03)',
- borderColor: 'rgba(255, 255, 255, 0.12)',
+ backgroundColor: fill.subtle,
+ borderColor: border.default,
+ transition: 'border-color 0.15s ease',
'&:hover': {
- backgroundColor: 'rgba(255, 255, 255, 0.05)',
+ backgroundColor: fill.primaryHover,
+ borderColor: border.primaryDefault,
}
}}
>