feat: Implement responsive design enhancements with new utility classes and improved layout for various components
This commit is contained in:
@@ -104,6 +104,17 @@
|
||||
}
|
||||
.quick-edit-wrap .quick-edit-button:hover { opacity: 1; }
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.quick-edit-wrap .quick-edit-button,
|
||||
.case-meta-item .quick-edit-button,
|
||||
.case-inline-field .quick-edit-compact {
|
||||
opacity: 0.95;
|
||||
pointer-events: auto;
|
||||
padding: 0.15rem 0.35rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Metadata-specific quick-edit: ensure edit button overlays without moving badges */
|
||||
.case-meta-item { position: relative; }
|
||||
.case-meta-item .quick-edit-button {
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
{% include 'atlas/partials/_viewing_case_as_part_of_collection.html' with nav_link_view="atlas:collection_case_displaysetup" %}
|
||||
<h2>Setup default display for case</h2>
|
||||
|
||||
<div id="root" class="dicom-viewer-root" data-images="{{casedetail.case.get_series_images_nested}}"
|
||||
style="box-sizing: border-box; background: #222; width: 100vw; height: 800px; max-width: 1600px;"
|
||||
<div id="root" class="dicom-viewer-root viewer-frame-setup" data-images="{{casedetail.case.get_series_images_nested}}"
|
||||
data-auto-cache-stack="true"
|
||||
{% if casedetail.default_viewerstate %}
|
||||
data-viewerstate={{ casedetail.default_viewerstate }}
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
<div id="question-timer-block" class="mb-3" title="This case has a view time limit of {{ effective_question_time_limit }} seconds.">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div><strong>Case view:</strong> <span id="question-timer" aria-live="polite"> </span></div>
|
||||
<div style="flex:1; max-width:320px;">
|
||||
<div class="progress" style="height:10px;">
|
||||
<div class="flex-max-320">
|
||||
<div class="progress progress-compact-sm">
|
||||
<div id="question-timer-progress-inner" class="progress-bar" role="progressbar" style="width:100%; background:var(--timer-color, #28a745);"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -105,9 +105,9 @@
|
||||
<div>
|
||||
|
||||
{% if question_completed %}
|
||||
<iframe id="viewer" style="width: 100%; height: 100%; border: none; padding: 0px; min-height: 700px" src="/ohif/viewer/dicomjson?url=https://www.penracourses.org.uk{% if case_number %}{% url 'atlas:collection_case_dicom_json_review' collection.pk case_number %}{% else %}{% url 'atlas:collection_case_dicom_json_review_legacy' collection.pk case.pk %}{% endif %}"></iframe>
|
||||
<iframe id="viewer" class="viewer-frame-ohif" src="/ohif/viewer/dicomjson?url=https://www.penracourses.org.uk{% if case_number %}{% url 'atlas:collection_case_dicom_json_review' collection.pk case_number %}{% else %}{% url 'atlas:collection_case_dicom_json_review_legacy' collection.pk case.pk %}{% endif %}"></iframe>
|
||||
{% else %}
|
||||
<iframe id="viewer" style="width: 100%; height: 100%; border: none; padding: 0px; min-height: 700px" src="/ohif/viewer/dicomjson?url=https://www.penracourses.org.uk{% if case_number %}{% url 'atlas:collection_case_dicom_json' collection.pk case_number %}{% else %}{% url 'atlas:collection_case_dicom_json_legacy' collection.pk case.pk %}{% endif %}"></iframe>
|
||||
<iframe id="viewer" class="viewer-frame-ohif" src="/ohif/viewer/dicomjson?url=https://www.penracourses.org.uk{% if case_number %}{% url 'atlas:collection_case_dicom_json' collection.pk case_number %}{% else %}{% url 'atlas:collection_case_dicom_json_legacy' collection.pk case.pk %}{% endif %}"></iframe>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
@@ -128,8 +128,7 @@
|
||||
|
||||
<details id="dicom-viewer-details" open>
|
||||
<summary>Viewer</summary>
|
||||
<div id="main_viewer" class="dicom-viewer-root"
|
||||
style="box-sizing: border-box; background: #222; width: 100%; height: 600px;"
|
||||
<div id="main_viewer" class="dicom-viewer-root viewer-frame-standard"
|
||||
data-auto-cache-stack="false"
|
||||
data-named-stacks='{{casedetail.get_case_named_stacks}}'
|
||||
></div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card border-secondary" style="min-width: 320px;">
|
||||
<div class="card border-secondary summary-card">
|
||||
<div class="card-body py-2 px-3">
|
||||
<div class="small text-muted">Feedback Summary</div>
|
||||
<div class="fw-semibold">{{ total_outstanding_feedback }} outstanding feedback item{{ total_outstanding_feedback|pluralize }}</div>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<h2 class="h4 mb-1">{{ collection.name }}</h2>
|
||||
<div class="text-muted small">Learner: <strong>{{ user }}</strong></div>
|
||||
</div>
|
||||
<div class="card border-secondary" style="min-width: 320px;">
|
||||
<div class="card border-secondary summary-card">
|
||||
<div class="card-body py-2 px-3">
|
||||
<div class="small text-muted">Attempt Progress</div>
|
||||
<div class="fw-semibold">{{ answer_count }} / {{ collection_length }} answered</div>
|
||||
<div class="progress mt-2" style="height: 8px;">
|
||||
<div class="progress progress-compact mt-2">
|
||||
<div class="progress-bar" role="progressbar" style="width: {% widthratio answer_count collection_length 100 %}%"></div>
|
||||
</div>
|
||||
<div class="mt-2 small">Started: {{ cid_user_exam.start_time }}</div>
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card border-secondary" style="min-width: 280px;">
|
||||
<div class="card border-secondary summary-card">
|
||||
<div class="card-body py-2 px-3">
|
||||
<div class="small text-muted">Progress</div>
|
||||
{% if not collection.review_only %}
|
||||
<div class="fw-semibold">{{ answer_count }} / {{ collection_length }} answered</div>
|
||||
<div class="progress mt-2" style="height: 8px;">
|
||||
<div class="progress progress-compact mt-2">
|
||||
<div class="progress-bar" role="progressbar" style="width: {% widthratio answer_count collection_length 100 %}%"></div>
|
||||
</div>
|
||||
{% else %}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h2 class="h4 mb-1">{{ collection.name }}</h2>
|
||||
<div class="text-muted small">Message hub for <strong>{{ target_label }}</strong></div>
|
||||
</div>
|
||||
<div class="card border-secondary" style="min-width: 320px;">
|
||||
<div class="card border-secondary summary-card">
|
||||
<div class="card-body py-2 px-3">
|
||||
<div class="small text-muted">Outstanding messages</div>
|
||||
<div class="fw-semibold {% if total_outstanding_messages %}text-danger{% endif %}">
|
||||
|
||||
@@ -103,8 +103,8 @@
|
||||
<small id="viewer-context" class="text-muted">No study/series selected</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body" style="position: relative; min-height: 450px;">
|
||||
<div id="uploadviewer" class="dicom-viewer-root" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 100%; height: 100%;"></div>
|
||||
<div class="card-body viewer-preupload-shell">
|
||||
<div id="uploadviewer" class="dicom-viewer-root viewer-preupload-root"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -30,8 +30,7 @@
|
||||
<div class="card">
|
||||
<div class="card-body p-2">
|
||||
{% with image_url_array_and_count=series.get_image_url_array_and_count %}
|
||||
<div id="root" class="dicom-viewer-root w-100" data-images="{{ image_url_array_and_count.0 }}"
|
||||
style="height: 600px; box-sizing: border-box; background: #222;" data-auto-cache-stack=false>
|
||||
<div id="root" class="dicom-viewer-root w-100 viewer-frame-standard" data-images="{{ image_url_array_and_count.0 }}" data-auto-cache-stack=false>
|
||||
</div>
|
||||
{% endwith %}
|
||||
</div>
|
||||
@@ -242,13 +241,13 @@
|
||||
|
||||
|
||||
<div id="clone-findings-modal" class="modal modal-blur fade" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered related-finding-modal" style="max-width: 700px;">
|
||||
<div class="modal-dialog modal-dialog-centered related-finding-modal modal-wide-md">
|
||||
<div class="modal-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="series-tag-consistency-modal" class="modal modal-blur fade" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered modal-xl" style="max-width: 1200px;">
|
||||
<div class="modal-dialog modal-dialog-centered modal-xl modal-wide-xl">
|
||||
<div class="modal-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h2 class="h4 mb-1">Messages Inbox</h2>
|
||||
<div class="text-muted small">All accessible conversation threads across collections.</div>
|
||||
</div>
|
||||
<div class="card border-secondary" style="min-width: 320px;">
|
||||
<div class="card border-secondary summary-card">
|
||||
<div class="card-body py-2 px-3">
|
||||
<div class="small text-muted">Pending acknowledgements</div>
|
||||
<div class="fw-semibold {% if total_needs_your_ack %}text-danger{% endif %}">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<textarea name="data" rows="18" style="width:100%">{% if request.POST.data %}{{ request.POST.data }}{% endif %}</textarea>
|
||||
<textarea name="data" rows="18" class="w-100">{% if request.POST.data %}{{ request.POST.data }}{% endif %}</textarea>
|
||||
<div style="margin-top:8px">
|
||||
<button type="submit" name="action" value="preview" class="btn btn-primary">Preview</button>
|
||||
<button type="submit" name="action" value="apply" class="btn btn-danger" onclick="return confirm('This will apply updates to matched trainee profiles. Are you sure?')">Apply updates</button>
|
||||
@@ -40,9 +40,9 @@
|
||||
<div>
|
||||
<span style="color:red">No match</span>
|
||||
<div>
|
||||
<div class="d-inline-flex align-items-center" style="gap:6px">
|
||||
<form hx-get="{% url 'generic:user_search' %}" hx-target="#user-results-{{ r.row_index }}" hx-swap="innerHTML" onsubmit="return false;" class="d-inline-flex align-items-center">
|
||||
<input type="text" name="q" id="user-search-input-{{ r.row_index }}" placeholder="Search users..." style="width:220px" />
|
||||
<div class="inline-search-row">
|
||||
<form hx-get="{% url 'generic:user_search' %}" hx-target="#user-results-{{ r.row_index }}" hx-swap="innerHTML" onsubmit="return false;" class="inline-search-row">
|
||||
<input type="text" name="q" id="user-search-input-{{ r.row_index }}" class="form-control form-control-sm search-input-compact" placeholder="Search users..." />
|
||||
<input type="hidden" name="row" value="{{ r.row_index }}" />
|
||||
<button type="submit" class="btn btn-sm btn-secondary">Search</button>
|
||||
</form>
|
||||
@@ -59,9 +59,9 @@
|
||||
{% else %}
|
||||
<div>
|
||||
<span style="color:red">No match</span>
|
||||
<div class="d-inline-flex align-items-center" style="gap:6px">
|
||||
<form hx-get="{% url 'generic:supervisor_search' %}" hx-target="#supervisor-results-{{ r.row_index }}" hx-swap="innerHTML" onsubmit="return false;" class="d-inline-flex align-items-center">
|
||||
<input type="text" name="q" id="supervisor-search-input-{{ r.row_index }}" placeholder="Search supervisors..." style="width:220px" />
|
||||
<div class="inline-search-row">
|
||||
<form hx-get="{% url 'generic:supervisor_search' %}" hx-target="#supervisor-results-{{ r.row_index }}" hx-swap="innerHTML" onsubmit="return false;" class="inline-search-row">
|
||||
<input type="text" name="q" id="supervisor-search-input-{{ r.row_index }}" class="form-control form-control-sm search-input-compact" placeholder="Search supervisors..." />
|
||||
<input type="hidden" name="row" value="{{ r.row_index }}" />
|
||||
<button type="submit" class="btn btn-sm btn-secondary">Search</button>
|
||||
</form>
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Shared responsive helpers for layout, forms, cards, and viewer surfaces. */
|
||||
|
||||
.summary-card {
|
||||
width: 100%;
|
||||
max-width: 22rem;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.summary-card {
|
||||
width: auto;
|
||||
min-width: 17.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control-max-300 {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.form-control-max-320 {
|
||||
width: 100%;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
.search-input-compact {
|
||||
width: min(100%, 220px);
|
||||
}
|
||||
|
||||
.inline-search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.viewer-frame-setup {
|
||||
box-sizing: border-box;
|
||||
background: #222;
|
||||
width: 100%;
|
||||
max-width: 1600px;
|
||||
height: min(72vh, 800px);
|
||||
min-height: 420px;
|
||||
}
|
||||
|
||||
.viewer-frame-standard {
|
||||
box-sizing: border-box;
|
||||
background: #222;
|
||||
width: 100%;
|
||||
height: min(68vh, 600px);
|
||||
min-height: 360px;
|
||||
}
|
||||
|
||||
.viewer-frame-ohif {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
padding: 0;
|
||||
min-height: min(70vh, 700px);
|
||||
}
|
||||
|
||||
.viewer-preupload-shell {
|
||||
position: relative;
|
||||
min-height: clamp(320px, 55vh, 450px);
|
||||
}
|
||||
|
||||
.viewer-preupload-root {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.modal-wide-md {
|
||||
max-width: min(700px, 96vw);
|
||||
}
|
||||
|
||||
.modal-wide-xl {
|
||||
max-width: min(1200px, 96vw);
|
||||
}
|
||||
|
||||
.progress-compact {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.progress-compact-sm {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.flex-max-320 {
|
||||
flex: 1;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
.flex-max-320 {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Shared responsive helpers for layout, forms, cards, and viewer surfaces. */
|
||||
|
||||
.summary-card {
|
||||
width: 100%;
|
||||
max-width: 22rem;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.summary-card {
|
||||
width: auto;
|
||||
min-width: 17.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control-max-300 {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.form-control-max-320 {
|
||||
width: 100%;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
.search-input-compact {
|
||||
width: min(100%, 220px);
|
||||
}
|
||||
|
||||
.inline-search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.viewer-frame-setup {
|
||||
box-sizing: border-box;
|
||||
background: #222;
|
||||
width: 100%;
|
||||
max-width: 1600px;
|
||||
height: min(72vh, 800px);
|
||||
min-height: 420px;
|
||||
}
|
||||
|
||||
.viewer-frame-standard {
|
||||
box-sizing: border-box;
|
||||
background: #222;
|
||||
width: 100%;
|
||||
height: min(68vh, 600px);
|
||||
min-height: 360px;
|
||||
}
|
||||
|
||||
.viewer-frame-ohif {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
padding: 0;
|
||||
min-height: min(70vh, 700px);
|
||||
}
|
||||
|
||||
.viewer-preupload-shell {
|
||||
position: relative;
|
||||
min-height: clamp(320px, 55vh, 450px);
|
||||
}
|
||||
|
||||
.viewer-preupload-root {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.modal-wide-md {
|
||||
max-width: min(700px, 96vw);
|
||||
}
|
||||
|
||||
.modal-wide-xl {
|
||||
max-width: min(1200px, 96vw);
|
||||
}
|
||||
|
||||
.progress-compact {
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.progress-compact-sm {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.flex-max-320 {
|
||||
flex: 1;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
.flex-max-320 {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -38,13 +38,13 @@
|
||||
<p>Please note users created this way bypass some of the validations so check details such as email addresses are correct</p>
|
||||
<div class="mb-2">
|
||||
<label for="input-format" class="form-label">Input format</label>
|
||||
<select id="input-format" class="form-select" style="width:300px">
|
||||
<select id="input-format" class="form-select form-control-max-300">
|
||||
<option value="spreadsheet">First,Last,Email,Grade,Supervisor,SupervisorEmail (spreadsheet)</option>
|
||||
<option value="name-supervisor-email-grade">User \t Educational Supervisor \t Email \t Grade</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<textarea id="csv" placeholder="Paste users content here" style="width: 300px; height: 100px;"></textarea><br/>
|
||||
<textarea id="csv" class="form-control form-control-max-300" rows="4" placeholder="Paste users content here"></textarea><br/>
|
||||
<input type="button" value="Load Data" _="on click createTable()" >
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
console.log(user)
|
||||
$("#users-list").append(`<li data-index="${i}">Name: <span class="name">${user.first_name} ${user.last_name}</span><br/>Email: <span class="email">${user.email}</span><br/>Grade: <span class="grade">${user.grade}</span><br/>Supervisor: <span class="supervisor_name">${user.supervisor_name || ''}</span><br/>
|
||||
<form>
|
||||
Supervisor email: <input class="supervisor-email-input" name="supervisor_email" type="text" value="${user.supervisor_email || ''}" placeholder="supervisor email" style="width: 320px; display: none;" /> <br/>
|
||||
Supervisor email: <input class="supervisor-email-input form-control form-control-sm form-control-max-320" name="supervisor_email" type="text" value="${user.supervisor_email || ''}" placeholder="supervisor email" style="display: none;" /> <br/>
|
||||
<input type="text" name="first_name" value="${user.first_name}" hidden>
|
||||
<input type="text" name="last_name" value="${user.last_name}" hidden>
|
||||
<input type="text" name="email" value="${user.email}" hidden>
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
{% endblock %}
|
||||
<link rel="stylesheet" href="{% static 'css/anatomy.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/forms.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/responsive-utils.css' %}">
|
||||
<style>
|
||||
|
||||
:root {
|
||||
|
||||
Reference in New Issue
Block a user