Skip to content
This repository was archived by the owner on Jan 28, 2026. It is now read-only.

Commit 283797c

Browse files
authored
Merge pull request #154 from DigitalProductInnovationAndDevelopment/development
Dark Mode & new search UI
2 parents c7c9536 + 2276eb0 commit 283797c

58 files changed

Lines changed: 9579 additions & 2904 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/routes/autocomplete.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,29 @@ router.get('/', async (req, res) => {
8080
}
8181
}
8282

83-
if (type === 'institution' && query.length >= 2) {
83+
if (type === 'institution' && query.length >= 1) {
8484
try {
85-
const url = `${OPENALEX_API_BASE}/institutions`;
86-
const params = { search: query, per_page: 10 };
85+
// Use OpenAlex autocomplete endpoint for better partial matching
86+
const url = `${OPENALEX_API_BASE}/autocomplete`;
87+
const params = {
88+
q: query,
89+
mailto: 'team@ourresearch.org'
90+
};
8791
const response = await axios.get(url, { params, headers: OPENALEX_HEADERS });
8892
const data = response.data;
89-
const results = (data.results || []).map(inst => ({
90-
id: inst.id,
91-
display_name: inst.display_name
92-
}));
93-
return res.json({ results });
93+
94+
// Filter results to only include institutions
95+
const institutionResults = (data.results || [])
96+
.filter(item => item.entity_type === 'institution')
97+
.map(inst => ({
98+
id: inst.id,
99+
display_name: inst.display_name
100+
}));
101+
102+
return res.json({ results: institutionResults });
94103
} catch (err) {
95-
return res.status(500).json({ results: [], error: 'Failed to fetch from OpenAlex' });
104+
console.error('OpenAlex autocomplete error:', err.message);
105+
return res.status(500).json({ results: [], error: 'Failed to fetch from OpenAlex autocomplete' });
96106
}
97107
}
98108

backend/routes/publications.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,7 @@ router.get('/keyword_trends', async (req, res) => {
146146
start_date,
147147
end_date,
148148
per_page = 200,
149-
years,
150-
limit
149+
institution_id
151150
} = req.query;
152151

153152
let filterParts = [];
@@ -159,6 +158,11 @@ router.get('/keyword_trends', async (req, res) => {
159158
if (keyword) {
160159
filterParts.push(`title_and_abstract.search:${keyword}`);
161160
}
161+
// Add institution filter if provided
162+
if (institution_id) {
163+
filterParts.push(`authorships.institutions.id:I${institution_id}`);
164+
}
165+
162166
// Only add date filters if start_date or end_date is provided
163167
if (start_date) {
164168
filterParts.push(`from_publication_date:${start_date}`);

frontend/package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"@testing-library/user-event": "^13.5.0",
99
"cors": "^2.8.5",
1010
"d3-geo": "^3.1.1",
11+
"ogl": "^1.0.11",
1112
"react": "^18.2.0",
1213
"react-datepicker": "^8.4.0",
1314
"react-dom": "^18.2.0",

frontend/src/App.jsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import React, { useState } from 'react';
22
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
3-
import { LandingPageLight } from './pages/light_mode/landing_light';
4-
import SearchPageLight from './pages/light_mode/search_light';
5-
import { AboutPage } from './pages/light_mode/about_light';
6-
import { PositionDetailLight } from './pages/light_mode/position_detail_light';
7-
import GraphViewLight from './pages/light_mode/graph_view_light';
8-
import WorldMapPapersPage from './pages/light_mode/WorldMapPapersPage';
3+
import { LandingPageLight } from './pages/home';
4+
import SearchPageLight from './pages/search';
5+
import { AboutPage } from './pages/about';
6+
import { PositionDetailLight } from './pages/trend_graphs';
7+
import GraphViewLight from './pages/collaboration_graph';
8+
import WorldMapPapersPage from './pages/world_map';
99

1010
function App() {
11-
const [isDarkMode, setIsDarkMode] = useState(false);
11+
const [isDarkMode, setIsDarkMode] = useState(true);
1212

1313
const toggleDarkMode = () => {
1414
setIsDarkMode(!isDarkMode);
@@ -21,11 +21,11 @@ function App() {
2121
<main>
2222
<Routes>
2323
<Route path="/" element={<LandingPageLight darkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />} />
24-
<Route path="/search" element={<SearchPageLight darkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />} />
24+
<Route path="/search" element={<SearchPageLight darkMode={isDarkMode} />} />
2525
<Route path="/graph-view" element={<GraphViewLight darkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />} />
2626
<Route path="/about" element={<AboutPage darkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />} />
27-
<Route path="/trends" element={<PositionDetailLight darkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />} />
28-
<Route path="/world-map" element={<WorldMapPapersPage darkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />} />
27+
<Route path="/trends" element={<PositionDetailLight darkMode={true} />} />
28+
<Route path="/world-map" element={<WorldMapPapersPage />} />
2929
</Routes>
3030
</main>
3131
</div>
Lines changed: 8 additions & 0 deletions
Loading

frontend/src/assets/styles/global.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ body.dark {
2323
color: var(--color-text-dark);
2424
}
2525

26+
/* Dark mode input placeholder styles */
27+
.dark input::placeholder {
28+
color: #888;
29+
opacity: 1;
30+
}
31+
32+
.dark input:-ms-input-placeholder {
33+
color: #888;
34+
}
35+
36+
.dark input::-ms-input-placeholder {
37+
color: #888;
38+
}
39+
2640
/* App layout */
2741
.app {
2842
width: 100%;

frontend/src/assets/styles/institutionDropdown.module.css

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,87 @@
11
.dropdownContainer {
22
position: relative;
33
width: 100%;
4-
max-width: 400px;
5-
margin-bottom: 1rem;
4+
margin-bottom: 0;
65
}
6+
77
.label {
88
font-weight: 600;
99
margin-bottom: 0.25rem;
1010
display: block;
1111
}
12+
1213
.inputWrapper {
14+
position: relative;
1315
display: flex;
1416
align-items: center;
1517
}
18+
1619
.input {
1720
width: 100%;
18-
padding: 0.5rem;
19-
border: 1px solid #ccc;
20-
border-radius: 4px 0 0 4px;
21+
padding: 0.75rem;
22+
border: 1px solid #e5e7eb;
23+
border-radius: 6px;
2124
outline: none;
2225
font-size: 1rem;
26+
background: #222;
27+
color: #fff;
2328
}
29+
2430
.toggleBtn {
25-
border: 1px solid #ccc;
26-
border-left: none;
27-
background: #f7f7f7;
28-
padding: 0.5rem 0.75rem;
29-
border-radius: 0 4px 4px 0;
31+
position: absolute;
32+
right: 32px;
33+
top: 50%;
34+
transform: translateY(-50%);
35+
border: none;
36+
background: transparent;
37+
padding: 0.25rem;
3038
cursor: pointer;
31-
font-size: 1rem;
39+
font-size: 0.75rem;
40+
color: #6b7280;
41+
z-index: 5;
42+
height: 24px;
43+
width: 24px;
44+
display: flex;
45+
align-items: center;
46+
justify-content: center;
3247
}
48+
3349
.dropdownList {
3450
position: absolute;
3551
top: 100%;
3652
left: 0;
3753
right: 0;
3854
max-height: 220px;
3955
overflow-y: auto;
40-
background: #fff;
56+
background: #222;
57+
color: #fff;
4158
border: 1px solid #ccc;
4259
border-top: none;
4360
z-index: 10;
44-
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
61+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
4562
}
63+
4664
.dropdownItem {
47-
padding: 0.5rem 1rem;
65+
padding: 0.75rem 1rem;
4866
cursor: pointer;
4967
transition: background 0.15s;
68+
background: #222;
69+
color: #fff;
5070
}
71+
5172
.dropdownItem:hover {
52-
background: #f0f0f0;
73+
background: #333;
74+
color: #fff;
5375
}
54-
.loading, .noResults {
76+
77+
.loading,
78+
.noResults {
5579
padding: 0.75rem 1rem;
56-
color: #888;
80+
color: #6b7280;
5781
text-align: center;
82+
font-size: 0.875rem;
5883
}
84+
5985
.selectedValue {
6086
margin-top: 0.5rem;
6187
font-size: 0.95rem;

0 commit comments

Comments
 (0)