Skip to content
This repository was archived by the owner on Jan 28, 2026. It is now read-only.
Merged
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
77 changes: 76 additions & 1 deletion backend/routes/publications.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ router.get('/', async (req, res) => {
...(search && { search })
};

const response = await axios.get(url, {
const response = await axios.get(url, {
params,
headers: OPENALEX_HEADERS
});
Expand Down Expand Up @@ -298,6 +298,81 @@ router.get('/keyword_trends', async (req, res) => {
}
});



// Route to get conference information for a list of DOIs
router.get('/conference-info', async (req, res) => {
try {
console.log('Conference-info route called');
const { dois } = req.query;
console.log('DOIs received:', dois);

if (!dois) {
return res.status(400).json({ error: 'DOIs parameter is required' });
}

// Split the DOIs string and extract just the DOI part from URLs
const doiList = Array.isArray(dois) ? dois : dois.split(',');
const extractedDois = doiList.map(doiUrl => {
// Extract just the DOI part from the full URL
const doiMatch = doiUrl.match(/https:\/\/doi\.org\/(.+)/);
return doiMatch ? doiMatch[1] : doiUrl;
});

console.log('Extracted DOIs:', extractedDois);
const results = [];

// Process each DOI with individual API calls
for (const doi of extractedDois) {
try {
console.log(`Processing DOI: ${doi}`);
const url = `https://api.crossref.org/works/${doi}`;
console.log(`CrossRef URL: ${url}`);

const response = await axios.get(url);
console.log(`Response status: ${response.status}`);

if (response.status !== 200) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = response.data;
const msg = data.message;
console.log(`Conference name: ${msg.event?.name}`);

const info = {
doi: doi,
title: msg.title?.[0] || null,
container: msg['container-title']?.[0] || null,
type: msg.type || null,
publisher: msg.publisher || null,
year: msg.issued?.['date-parts']?.[0]?.[0] || null,
event: {
name: msg.event?.name || null
}
};

results.push(info);

// Small delay to avoid overwhelming the API
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
console.error(`Error processing DOI ${doi}:`, error);
results.push({
doi: doi,
error: 'Failed to fetch conference information'
});
}
}

console.log('Results:', results);
res.json({ results });
} catch (error) {
console.error('Error in conference-info route:', error);
res.status(500).json({ error: 'Failed to fetch conference information' });
}
});

//get a single publication
router.get('/:id', async (req, res) => {
try {
Expand Down
40 changes: 22 additions & 18 deletions frontend/src/assets/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ body.dark {

/* App layout */
.app {
width: 100%;
width: 100vw;
min-height: 100vh;
margin: 0;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
}

.main-content {
Expand All @@ -51,9 +55,9 @@ body.dark {

/* Utility classes */
.container {
max-width: var(--breakpoint-desktop);
margin: 0 auto;
padding: 0 var(--spacing-md);
width: 100vw;
margin: 0;
padding: 0;
}

.text-center {
Expand Down Expand Up @@ -82,35 +86,37 @@ body.dark {

html,
body {
overflow-y: scroll !important;
/* Always show vertical scrollbar */
height: 100%;
overflow-x: hidden !important;
overflow-y: auto !important;
/* Allow vertical scrolling, prevent horizontal overflow */
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
}

/* For Webkit browsers (Chrome, Safari, Edge) */
html::-webkit-scrollbar,
body::-webkit-scrollbar {
width: 12px;
width: 0px;
display: none;
}

html::-webkit-scrollbar-thumb,
body::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 6px;
display: none;
}

html::-webkit-scrollbar-track,
body::-webkit-scrollbar-track {
background: #f1f1f1;
display: none;
}

/* For Firefox */
html,
body {
scrollbar-width: auto;
scrollbar-color: #ccc #f1f1f1;
scrollbar-width: none;
scrollbar-color: transparent transparent;
}

/* === DESIGN SYSTEM TOKENS (HSL) === */
Expand Down Expand Up @@ -323,11 +329,9 @@ body {

/* Container */
.container {
max-width: 1200px;
margin-left: auto;
margin-right: auto;
padding-left: 1rem;
padding-right: 1rem;
width: 100%;
margin: 0;
padding: 0;
}

/* Responsive text center */
Expand Down
195 changes: 195 additions & 0 deletions frontend/src/components/animated/Lighting/Lightining.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import { useRef, useEffect } from "react";
import "./lightning.css";

const Lightning = ({
hue = 230,
xOffset = 0,
speed = 1,
intensity = 1,
size = 1,
}) => {
const canvasRef = useRef(null);

useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;

const resizeCanvas = () => {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
};
resizeCanvas();
window.addEventListener("resize", resizeCanvas);

const gl = canvas.getContext("webgl");
if (!gl) {
console.error("WebGL not supported");
return;
}

const vertexShaderSource = `
attribute vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
}
`;

const fragmentShaderSource = `
precision mediump float;
uniform vec2 iResolution;
uniform float iTime;
uniform float uHue;
uniform float uXOffset;
uniform float uSpeed;
uniform float uIntensity;
uniform float uSize;

#define OCTAVE_COUNT 10

vec3 hsv2rgb(vec3 c) {
vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0,4.0,2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
return c.z * mix(vec3(1.0), rgb, c.y);
}

float hash11(float p) {
p = fract(p * .1031);
p *= p + 33.33;
p *= p + p;
return fract(p);
}

float hash12(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * .1031);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}

mat2 rotate2d(float theta) {
float c = cos(theta);
float s = sin(theta);
return mat2(c, -s, s, c);
}

float noise(vec2 p) {
vec2 ip = floor(p);
vec2 fp = fract(p);
float a = hash12(ip);
float b = hash12(ip + vec2(1.0, 0.0));
float c = hash12(ip + vec2(0.0, 1.0));
float d = hash12(ip + vec2(1.0, 1.0));

vec2 t = smoothstep(0.0, 1.0, fp);
return mix(mix(a, b, t.x), mix(c, d, t.x), t.y);
}

float fbm(vec2 p) {
float value = 0.0;
float amplitude = 0.5;
for (int i = 0; i < OCTAVE_COUNT; ++i) {
value += amplitude * noise(p);
p *= rotate2d(0.45);
p *= 2.0;
amplitude *= 0.5;
}
return value;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
vec2 uv = fragCoord / iResolution.xy;
uv = 2.0 * uv - 1.0;
uv.x *= iResolution.x / iResolution.y;
uv.x += uXOffset;

uv += 2.0 * fbm(uv * uSize + 0.8 * iTime * uSpeed) - 1.0;

float dist = abs(uv.x);
vec3 baseColor = hsv2rgb(vec3(uHue / 360.0, 0.7, 0.8));
vec3 col = baseColor * pow(mix(0.0, 0.07, hash11(iTime * uSpeed)) / dist, 1.0) * uIntensity;
col = pow(col, vec3(1.0));
fragColor = vec4(col, 1.0);
}

void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}
`;

const compileShader = (
source,
type
) => {
const shader = gl.createShader(type);
if (!shader) return null;
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error("Shader compile error:", gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
};

const vertexShader = compileShader(vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = compileShader(
fragmentShaderSource,
gl.FRAGMENT_SHADER
);
if (!vertexShader || !fragmentShader) return;

const program = gl.createProgram();
if (!program) return;
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error("Program linking error:", gl.getProgramInfoLog(program));
return;
}
gl.useProgram(program);

const vertices = new Float32Array([
-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1,
]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

const aPosition = gl.getAttribLocation(program, "aPosition");
gl.enableVertexAttribArray(aPosition);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);

const iResolutionLocation = gl.getUniformLocation(program, "iResolution");
const iTimeLocation = gl.getUniformLocation(program, "iTime");
const uHueLocation = gl.getUniformLocation(program, "uHue");
const uXOffsetLocation = gl.getUniformLocation(program, "uXOffset");
const uSpeedLocation = gl.getUniformLocation(program, "uSpeed");
const uIntensityLocation = gl.getUniformLocation(program, "uIntensity");
const uSizeLocation = gl.getUniformLocation(program, "uSize");

const startTime = performance.now();
const render = () => {
resizeCanvas();
gl.viewport(0, 0, canvas.width, canvas.height);
gl.uniform2f(iResolutionLocation, canvas.width, canvas.height);
const currentTime = performance.now();
gl.uniform1f(iTimeLocation, (currentTime - startTime) / 1000.0);
gl.uniform1f(uHueLocation, hue);
gl.uniform1f(uXOffsetLocation, xOffset);
gl.uniform1f(uSpeedLocation, speed);
gl.uniform1f(uIntensityLocation, intensity);
gl.uniform1f(uSizeLocation, size);
gl.drawArrays(gl.TRIANGLES, 0, 6);
requestAnimationFrame(render);
};
requestAnimationFrame(render);

return () => {
window.removeEventListener("resize", resizeCanvas);
};
}, [hue, xOffset, speed, intensity, size]);

return <canvas ref={canvasRef} className="lightning-container" />;
};

export default Lightning;
5 changes: 5 additions & 0 deletions frontend/src/components/animated/Lighting/lightning.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.lightning-container {
width: 100%;
height: 100%;
position: relative;
}
14 changes: 14 additions & 0 deletions frontend/src/components/animated/TextType/texttype.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.text-type {
display: inline-block;
white-space: pre-wrap;
}

.text-type__cursor {
margin-left: 0.25rem;
display: inline-block;
opacity: 1;
}

.text-type__cursor--hidden {
display: none;
}
Loading
Loading