Skip to content
Open
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
81 changes: 79 additions & 2 deletions packages/apps/esm-login-app/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,81 @@
# openmrs-esm-login-app

openmrs-esm-login-app is responsible for rendering the loading page,
the login page, and the location picker.
openmrs-esm-login-app is responsible for rendering the loading page, the login page, and the location picker.

## Configuration

The login page can be customized through configuration. This allows implementers to:

- Choose from multiple layouts (default or split-screen)
- Customize backgrounds (colors, images, or gradients)
- Brand the login page with custom titles, subtitles, and logos
- Style the login card and buttons
- Add custom links and help text
- Configure the footer with additional logos

See the [configuration schema](src/config-schema.ts) for all available options.

## Configuration Examples

### Split-Screen Layout with Image Background

```json
{
"@openmrs/esm-login-app": {
"layout": {
"type": "split-screen",
"columnPosition": "right"
},
"background": {
"type": "image",
"value": "https://example.com/hospital-bg.jpg"
}
}
}
```

### Color Background

```json
{
"@openmrs/esm-login-app": {
"background": {
"type": "color",
"value": "#0066cc"
}
}
}
```

### Gradient Background

```json
{
"@openmrs/esm-login-app": {
"background": {
"type": "gradient",
"value": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
}
}
}
```

### Custom Branding

```json
{
"@openmrs/esm-login-app": {
"branding": {
"title": "Welcome to My Clinic",
"subtitle": "Electronic Medical Records System"
},
"logo": {
"src": "https://example.com/logo.png",
"alt": "My Clinic"
},
"button": {
"backgroundColor": "#0071c5"
}
}
}
```
40 changes: 40 additions & 0 deletions packages/apps/esm-login-app/__mocks__/config.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,44 @@ export const mockConfig: ConfigSchema = {
additionalLogos: [],
},
showPasswordOnSeparateScreen: true,
background: {
type: 'default',
value: '',
alt: 'Background Image',
size: 'cover',
position: 'center',
repeat: 'no-repeat',
attachment: 'scroll',
overlay: {
enabled: false,
color: 'rgba(0, 0, 0, 0.3)',
opacity: 0.3,
blendMode: 'normal',
},
},
layout: {
type: 'default' as const,
columnPosition: 'center' as const,
showLogo: true,
showFooter: true,
},
card: {
backgroundColor: '',
borderRadius: '',
width: '',
padding: '',
boxShadow: '',
},
button: {
backgroundColor: '',
textColor: '',
},
branding: {
title: '',
subtitle: '',
customText: '',
helpText: '',
contactEmail: '',
customLinks: [],
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React, { useMemo } from 'react';
import { useConfig } from '@openmrs/esm-framework';
import { type ConfigSchema } from '../config-schema';
import styles from './background-wrapper.scss';

interface BackgroundWrapperProps {
children: React.ReactNode;
}

const BackgroundWrapper: React.FC<BackgroundWrapperProps> = ({ children }) => {
const config = useConfig<ConfigSchema>();
const { layout, background } = config;

const backgroundStyles = useMemo(() => {
const style: React.CSSProperties = {};

switch (background.type) {
case 'color':
if (background.value) {
style.backgroundColor = background.value;
}
break;

case 'image':
if (background.value) {
// Simple URL-based approach - let browser handle loading
style.backgroundImage = `url(${background.value})`;
style.backgroundSize = background.size || 'cover';
style.backgroundPosition = background.position || 'center';
style.backgroundRepeat = background.repeat || 'no-repeat';
style.backgroundAttachment = background.attachment || 'scroll';
}
break;

case 'gradient':
if (background.value) {
style.background = background.value;
Copy link
Member

@sherrif10 sherrif10 Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @UjjawalPrabhat , We need Loginbackground to be configurable, i went ahead and tested your code .Check this out.
loginbackground.webm These changes override the default login image.

Copy link
Author

@UjjawalPrabhat UjjawalPrabhat Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @sherrif10, the Logo change config you're referring to wasn't implemented by me. It was there from before and therefore the logo is editable. If you're referring to background change then that is available in a separate section called as background.
Do you want me to make the Logo constant?
Also please let me know if there's any other changes or enhancements required.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the login page to look like this . Share the vedio of your changes before and after
unnamed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sherrif10 could you send the images used in this the login page?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @UjjawalPrabhat , We want to come up with something like that in the image i shared, FYI , Login page is already configurable, the only changes needed is to make login page appear like that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sherrif10 I'm on it. I was talking about the images used like the 3 doctor's and logo image used in the login page. It'd be easier for me to configure then

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it needs to be configurable and when the configuration is set to default, Default OMRS login page should appear, Then you should consider making it appear left or right on the login page.

}
break;

default:
// Use default styling
break;
}

return style;
}, [background]);

const overlayStyles = useMemo(() => {
if (!background.overlay.enabled) {
return {};
}

return {
backgroundColor: background.overlay.color,
opacity: background.overlay.opacity,
mixBlendMode: background.overlay.blendMode || 'normal',
};
}, [background]);

const hasCustomBackground = background.type !== 'default' && background.value;
const hasOverlay = background.overlay.enabled && hasCustomBackground;

// Split-screen layout: Background image on one side, login card on opposite side
if (layout.type === 'split-screen' && background.type === 'image' && background.value) {
// Determine which side gets the background image based on columnPosition
// If card is on left, bg is on right. If card is on right, bg is on left.
// If card is center, bg is on left by default
const bgPosition = layout.columnPosition === 'right' ? 'left' : 'right';

return (
<div className={`${styles.backgroundWrapper} ${styles.splitScreenContainer}`}>
<div
className={`${styles.backgroundPanel} ${styles[`bgPosition-${bgPosition}`]}`}
style={{
backgroundImage: `url(${background.value})`,
backgroundSize: background.size || 'cover',
backgroundPosition: background.position || 'center',
backgroundRepeat: background.repeat || 'no-repeat',
}}
/>
<div className={styles.content}>{children}</div>
</div>
);
}

// Default layout: Simple background with optional overlay
return (
<div
className={`${styles.backgroundWrapper} ${hasCustomBackground ? styles.customBackground : ''}`}
style={backgroundStyles}
>
{hasOverlay && <div className={styles.overlay} style={overlayStyles} />}
<div className={styles.content}>{children}</div>
</div>
);
};

export default BackgroundWrapper;
96 changes: 96 additions & 0 deletions packages/apps/esm-login-app/src/background/background-wrapper.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
@use '@carbon/layout';
@use '@openmrs/esm-styleguide/src/vars' as *;

.backgroundWrapper {
min-height: 100vh;
position: relative;

&.customBackground {
// Ensure proper background attachment
background-attachment: scroll;

@media (min-width: 769px) {
// Enable fixed backgrounds on desktop for better visual effect
&[style*='background-attachment: fixed'] {
background-attachment: fixed;
}
}

@media (max-width: 768px) {
// Always use scroll on mobile for better performance
background-attachment: scroll !important;
}
}
}

.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
pointer-events: none;
transition: opacity 0.3s ease-in-out;
}

.content {
position: relative;
z-index: 2;
min-height: 100vh;
display: flex;
flex-direction: column;

.customBackground & {
// Add subtle backdrop for better content readability on custom backgrounds
backdrop-filter: blur(0.5px);
}
}

// Split-screen layout styles
.splitScreenContainer {
display: flex;
min-height: 100vh;
position: relative;
overflow: hidden;

.content {
position: relative;
z-index: 2;
width: 100%;
}

@media (max-width: 768px) {
// On mobile, stack vertically with background on top
flex-direction: column;

.backgroundPanel {
position: relative !important;
width: 100% !important;
height: 30vh !important;
left: 0 !important;
right: 0 !important;
}
}
}

.backgroundPanel {
position: absolute;
top: 0;
bottom: 0;
width: 50%;
z-index: 1;

&.bgPosition-left {
left: 0;
}

&.bgPosition-right {
right: 0;
}

@media (min-width: 769px) and (max-width: 1024px) {
// On tablets, adjust background width
width: 40%;
}
}
Loading