layout improvements

This commit is contained in:
overcuriousity 2025-07-24 19:18:41 +02:00
parent f92219f61f
commit f76999ed2e
2 changed files with 275 additions and 96 deletions

View File

@ -39,10 +39,22 @@ const { authenticated, userEmail, userId } = authResult;
</div>
<!-- Contribution Options -->
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 2rem; margin-bottom: 3rem;">
<!-- WRAPPER -->
<div
style="
display:grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap:2rem;
align-items:stretch;
margin-bottom: 2rem;
"
>
<!-- Tools, Methods & Concepts -->
<div class="card" style="padding: 2rem; border-left: 4px solid var(--color-primary); cursor: pointer; transition: var(--transition-fast);" onclick="window.location.href='/contribute/tool'">
<div class="card"
style="padding: 2rem; border-left: 4px solid var(--color-primary); cursor: pointer; transition: var(--transition-fast);
display:flex; flex-direction:column;"
onclick="window.location.href='/contribute/tool'">
<div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
<div style="width: 48px; height: 48px; background-color: var(--color-primary); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
@ -63,14 +75,17 @@ const { authenticated, userEmail, userId } = authResult;
<span class="badge" style="background-color: var(--color-concept); color: white;">Concepts</span>
</div>
<div style="display: flex; gap: 1rem;">
<div style="margin-top:auto; display:flex; gap:1rem;">
<a href="/contribute/tool" class="btn btn-primary" style="flex: 1;">Add New Entry</a>
<a href="/contribute/tool?mode=browse" class="btn btn-secondary" style="flex: 1;">Edit Existing</a>
</div>
</div>
<!-- Knowledgebase Articles -->
<div class="card" style="padding: 2rem; border-left: 4px solid var(--color-accent); cursor: pointer; transition: var(--transition-fast);" onclick="window.location.href='/contribute/knowledgebase'">
<div class="card"
style="padding: 2rem; border-left: 4px solid var(--color-accent); cursor: pointer; transition: var(--transition-fast);
display:flex; flex-direction:column;"
onclick="window.location.href='/contribute/knowledgebase'">
<div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
<div style="width: 48px; height: 48px; background-color: var(--color-accent); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
@ -96,14 +111,16 @@ const { authenticated, userEmail, userId } = authResult;
<span class="badge badge-secondary">Case Studies</span>
</div>
<div style="display: flex; gap: 1rem;">
<div style="margin-top:auto; display:flex; gap:1rem;">
<a href="/contribute/knowledgebase" class="btn btn-accent" style="flex: 1;">Write Article</a>
<a href="/knowledgebase" class="btn btn-secondary" style="flex: 1;">View Articles</a>
</div>
</div>
<!-- Issues & Improvements -->
<div class="card" style="padding: 2rem; border-left: 4px solid var(--color-warning); grid-column: 1 / -1;">
<div class="card"
style="padding: 2rem; border-left: 4px solid var(--color-accent); cursor: pointer; transition: var(--transition-fast);
display:flex; flex-direction:column;">
<div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
<div style="width: 48px; height: 48px; background-color: var(--color-warning); border-radius: 0.5rem; display: flex; align-items: center; justify-content: center;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
@ -116,7 +133,7 @@ const { authenticated, userEmail, userId } = authResult;
</div>
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 2rem; align-items: center;">
<div>
<div style="display:flex; flex-direction:column;">
<p style="margin-bottom: 1rem; line-height: 1.6;">
Found incorrect information, broken links, or have suggestions for improvements?
Report issues directly in our Git repository or suggest enhancements to existing entries.
@ -138,8 +155,13 @@ const { authenticated, userEmail, userId } = authResult;
</a>
</div>
</div>
<!-- Push this actions block down if you add more later -->
<div style="margin-top:auto;"></div>
</div>
</div>
</div>
<!-- Guidelines -->
<div class="card" style="margin-bottom: 2rem;">

157
src/utils/api.ts Normal file
View File

@ -0,0 +1,157 @@
// src/utils/api.ts
// Standard JSON headers for all API responses
const JSON_HEADERS = {
'Content-Type': 'application/json'
} as const;
/**
* Base function to create consistent API responses
* All other response helpers use this internally
*/
export function createAPIResponse(data: any, status: number = 200, additionalHeaders?: Record<string, string>): Response {
const headers = additionalHeaders
? { ...JSON_HEADERS, ...additionalHeaders }
: JSON_HEADERS;
return new Response(JSON.stringify(data), {
status,
headers
});
}
/**
* Success responses (2xx status codes)
*/
export const apiResponse = {
// 200 - Success with data
success: (data: any = { success: true }): Response =>
createAPIResponse(data, 200),
// 201 - Created (for contribution submissions, uploads, etc.)
created: (data: any = { success: true }): Response =>
createAPIResponse(data, 201),
// 202 - Accepted (for async operations)
accepted: (data: any = { success: true, message: 'Request accepted for processing' }): Response =>
createAPIResponse(data, 202)
};
/**
* Client error responses (4xx status codes)
*/
export const apiError = {
// 400 - Bad Request
badRequest: (message: string = 'Bad request', details?: string[]): Response =>
createAPIResponse({
success: false,
error: message,
...(details && { details })
}, 400),
// 401 - Unauthorized
unauthorized: (message: string = 'Authentication required'): Response =>
createAPIResponse({ success: false, error: message }, 401),
// 403 - Forbidden
forbidden: (message: string = 'Access denied'): Response =>
createAPIResponse({ success: false, error: message }, 403),
// 404 - Not Found
notFound: (message: string = 'Resource not found'): Response =>
createAPIResponse({ success: false, error: message }, 404),
// 422 - Unprocessable Entity (validation errors)
validation: (message: string = 'Validation failed', details?: string[]): Response =>
createAPIResponse({
success: false,
error: message,
...(details && { details })
}, 422),
// 429 - Rate Limited
rateLimit: (message: string = 'Rate limit exceeded. Please wait before trying again.'): Response =>
createAPIResponse({ success: false, error: message }, 429)
};
/**
* Server error responses (5xx status codes)
*/
export const apiServerError = {
// 500 - Internal Server Error
internal: (message: string = 'Internal server error'): Response =>
createAPIResponse({ success: false, error: message }, 500),
// 502 - Bad Gateway (external service issues)
badGateway: (message: string = 'External service error'): Response =>
createAPIResponse({ success: false, error: message }, 502),
// 503 - Service Unavailable
unavailable: (message: string = 'Service temporarily unavailable'): Response =>
createAPIResponse({ success: false, error: message }, 503),
// 504 - Gateway Timeout
timeout: (message: string = 'Request timeout'): Response =>
createAPIResponse({ success: false, error: message }, 504)
};
/**
* Specialized response helpers for common patterns
*/
export const apiSpecial = {
// JSON parsing error
invalidJSON: (): Response =>
apiError.badRequest('Invalid JSON in request body'),
// Missing required fields
missingRequired: (fields: string[]): Response =>
apiError.badRequest(`Missing required fields: ${fields.join(', ')}`),
// Empty request body
emptyBody: (): Response =>
apiError.badRequest('Request body cannot be empty'),
// File upload responses
uploadSuccess: (data: { url: string; filename: string; size: number; storage: string }): Response =>
apiResponse.created(data),
uploadFailed: (error: string): Response =>
apiServerError.internal(`Upload failed: ${error}`),
// Contribution responses
contributionSuccess: (data: { prUrl?: string; branchName?: string; message: string }): Response =>
apiResponse.created({ success: true, ...data }),
contributionFailed: (error: string): Response =>
apiServerError.internal(`Contribution failed: ${error}`)
};
export const apiWithHeaders = {
// Success with custom headers (e.g., Set-Cookie)
successWithHeaders: (data: any, headers: Record<string, string>): Response =>
createAPIResponse(data, 200, headers),
// Redirect response
redirect: (location: string, temporary: boolean = true): Response =>
new Response(null, {
status: temporary ? 302 : 301,
headers: { 'Location': location }
})
};
export async function handleAPIRequest<T>(
operation: () => Promise<T>,
errorMessage: string = 'Request processing failed'
): Promise<T | Response> {
try {
return await operation();
} catch (error) {
console.error(`API Error: ${errorMessage}:`, error);
return apiServerError.internal(errorMessage);
}
}
export const createAuthErrorResponse = apiError.unauthorized;
export const createBadRequestResponse = apiError.badRequest;
export const createSuccessResponse = apiResponse.success;