Flowchart Updated
@ -30,21 +30,14 @@ const configs = {
|
||||
sample: {
|
||||
subject: 'SIF Form received for Project',
|
||||
fields: [
|
||||
// Customer Information
|
||||
'Principal_Investigator', 'Email', 'Company_Institution', 'Contact_Number', 'Address', 'City', 'State', 'Pin',
|
||||
'Secondary_Contact', 'Secondary_Email', 'Secondary_Company_Institution', 'Secondary_Contact_Number',
|
||||
|
||||
// Sample Information
|
||||
'Project_Title', 'Number_of_Samples', 'Sample_Type', 'Sample_Type_Other', 'Sample_Source', 'Sample_Source_Other',
|
||||
'Pathogenicity', 'Sample_Remarks',
|
||||
|
||||
// Service Information
|
||||
'Service_Requested', 'Service_Requested_Other', 'Type_of_Library', 'Type_of_Library_Other',
|
||||
'Required_Library_Size', 'Required_Library_Size_Other', 'Index_Information', 'Kit_Information',
|
||||
'Sequencing_Platform', 'Sequencing_Platform_Other', 'Sequencing_Read_Length', 'Sequencing_Read_Length_Other',
|
||||
'Total_Data_Requirement', 'Service_Remarks',
|
||||
|
||||
// Bioinformatics Information
|
||||
'Analysis_Requested', 'Analysis_Details', 'Reference_Genome_Available', 'Genome_Size', 'Special_Consideration'
|
||||
],
|
||||
required: [
|
||||
@ -58,6 +51,24 @@ const configs = {
|
||||
}
|
||||
};
|
||||
|
||||
// Serial number tracker
|
||||
let serialTracker = {};
|
||||
function generateSerialNumber() {
|
||||
const today = new Date();
|
||||
const dateKey = today.toISOString().slice(0, 10); // "YYYY-MM-DD"
|
||||
if (!serialTracker[dateKey]) {
|
||||
serialTracker[dateKey] = 1;
|
||||
} else {
|
||||
serialTracker[dateKey] += 1;
|
||||
}
|
||||
const serialNum = String(serialTracker[dateKey]).padStart(2, '0');
|
||||
return {
|
||||
serialNum,
|
||||
formatted: `Operify Tech. ${today.getFullYear()}.${String(today.getMonth() + 1).padStart(2, '0')}.${String(today.getDate()).padStart(2, '0')}.${serialNum}`,
|
||||
dateString: dateKey
|
||||
};
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
function isValidEmail(email) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
@ -77,7 +88,6 @@ export async function GET() {
|
||||
|
||||
export async function POST(request) {
|
||||
try {
|
||||
// Parse form data
|
||||
const formData = await request.formData();
|
||||
const data = {};
|
||||
const files = {};
|
||||
@ -92,7 +102,6 @@ export async function POST(request) {
|
||||
|
||||
const form_type = data.form_type;
|
||||
|
||||
// Validate form type
|
||||
if (!form_type || !configs[form_type]) {
|
||||
return NextResponse.json({
|
||||
error: 'Invalid form type: ' + (form_type || 'missing')
|
||||
@ -102,7 +111,6 @@ export async function POST(request) {
|
||||
const config = configs[form_type];
|
||||
const errors = [];
|
||||
|
||||
// Validate required fields
|
||||
for (const required_field of config.required) {
|
||||
if (!data[required_field] || String(data[required_field]).trim() === '') {
|
||||
errors.push(`The "${fieldName(required_field)}" field is required.`);
|
||||
@ -111,37 +119,28 @@ export async function POST(request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate file upload for career form
|
||||
if (form_type === 'career') {
|
||||
const fileField = config.file_field;
|
||||
const uploadedFile = files[fileField];
|
||||
|
||||
if (!uploadedFile || uploadedFile.size === 0) {
|
||||
errors.push('Please upload your resume.');
|
||||
} else {
|
||||
const allowedExtensions = ['pdf', 'doc', 'docx'];
|
||||
const fileName = uploadedFile.name.toLowerCase();
|
||||
const fileExtension = fileName.split('.').pop();
|
||||
|
||||
const fileExtension = uploadedFile.name.toLowerCase().split('.').pop();
|
||||
if (!allowedExtensions.includes(fileExtension)) {
|
||||
errors.push('Invalid file type. Please upload a PDF, DOC, or DOCX file.');
|
||||
}
|
||||
|
||||
if (uploadedFile.size > 10 * 1024 * 1024) { // 10MB limit
|
||||
if (uploadedFile.size > 10 * 1024 * 1024) {
|
||||
errors.push('File is too large. Maximum size is 10MB.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
return NextResponse.json({
|
||||
error: errors.join(' ')
|
||||
}, { status: 400 });
|
||||
return NextResponse.json({ error: errors.join(' ') }, { status: 400 });
|
||||
}
|
||||
|
||||
// Construct email body
|
||||
let emailBody = `<h2>${config.subject}</h2><table style="border: 1px solid #b5b5b5; padding: 5px;">`;
|
||||
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
if (config.fields.includes(key) && key !== 'form_type' && key !== 'sample_details') {
|
||||
emailBody += `<tr>
|
||||
@ -151,7 +150,6 @@ export async function POST(request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add file info if uploaded
|
||||
if (form_type === 'career' && files.resume) {
|
||||
emailBody += `<tr>
|
||||
<td style="border: 1px solid #b5b5b5; padding: 5px;"><strong>Resume</strong></td>
|
||||
@ -159,20 +157,17 @@ export async function POST(request) {
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
// Add sample details for sample form
|
||||
if (form_type === 'sample' && data.sample_details) {
|
||||
try {
|
||||
const sampleDetails = JSON.parse(data.sample_details);
|
||||
if (sampleDetails && sampleDetails.length > 0) {
|
||||
if (sampleDetails.length > 0) {
|
||||
emailBody += `<tr>
|
||||
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 10px; background-color: #e8f5f3; text-align: center;"><strong>SAMPLE DETAILS</strong></td>
|
||||
</tr>`;
|
||||
|
||||
sampleDetails.forEach((sample, index) => {
|
||||
emailBody += `<tr>
|
||||
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 8px; background-color: #f0f8f5; font-weight: bold;">Sample ${index + 1}</td>
|
||||
</tr>`;
|
||||
|
||||
Object.entries(sample).forEach(([key, value]) => {
|
||||
if (value && String(value).trim() !== '') {
|
||||
emailBody += `<tr>
|
||||
@ -183,25 +178,16 @@ export async function POST(request) {
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error parsing sample details:', error);
|
||||
} catch {
|
||||
emailBody += `<tr>
|
||||
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 5px; color: red;">Error: Could not parse sample details</td>
|
||||
</tr>`;
|
||||
}
|
||||
}
|
||||
|
||||
emailBody += '</table>';
|
||||
|
||||
// Determine reply-to email based on form type
|
||||
let replyToEmail;
|
||||
if (form_type === 'sample') {
|
||||
replyToEmail = data.Email;
|
||||
} else {
|
||||
replyToEmail = data.email;
|
||||
}
|
||||
let replyToEmail = form_type === 'sample' ? data.Email : data.email;
|
||||
|
||||
// Create transporter
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: 'smtp.gmail.com',
|
||||
port: 587,
|
||||
@ -212,17 +198,24 @@ export async function POST(request) {
|
||||
},
|
||||
});
|
||||
|
||||
// Prepare email options
|
||||
// SERIAL NUMBER LOGIC
|
||||
let serialInfo;
|
||||
if (form_type === 'sample') {
|
||||
serialInfo = generateSerialNumber();
|
||||
}
|
||||
|
||||
// Internal mail
|
||||
const mailOptions = {
|
||||
from: `${emailConfig.from_email_name} <${emailConfig.from_email}>`,
|
||||
to: `${emailConfig.to_email_name} <${emailConfig.to_email}>`,
|
||||
replyTo: replyToEmail || emailConfig.from_email,
|
||||
subject: config.subject,
|
||||
subject: form_type === 'sample'
|
||||
? `${data.Company_Institution} | ${data.Principal_Investigator} | ${serialInfo.dateString} | ${serialInfo.formatted}`
|
||||
: config.subject,
|
||||
html: emailBody,
|
||||
text: emailBody.replace(/<[^>]*>/g, ''), // Strip HTML for text version
|
||||
text: emailBody.replace(/<[^>]*>/g, '')
|
||||
};
|
||||
|
||||
// Add attachment for career form
|
||||
if (form_type === 'career' && files.resume) {
|
||||
const fileBuffer = await files.resume.arrayBuffer();
|
||||
mailOptions.attachments = [{
|
||||
@ -231,18 +224,24 @@ export async function POST(request) {
|
||||
}];
|
||||
}
|
||||
|
||||
// Send email
|
||||
await transporter.sendMail(mailOptions);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: config.successMessage
|
||||
});
|
||||
// PI email for sample form
|
||||
if (form_type === 'sample') {
|
||||
const piMailOptions = {
|
||||
from: `${emailConfig.from_email_name} <${emailConfig.from_email}>`,
|
||||
to: `${data.Principal_Investigator} <${data.Email}>`,
|
||||
subject: `SIF Form received for Project with - ${serialInfo.formatted}`,
|
||||
html: emailBody,
|
||||
text: emailBody.replace(/<[^>]*>/g, '')
|
||||
};
|
||||
await transporter.sendMail(piMailOptions);
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, message: config.successMessage });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Email sending error:', error);
|
||||
return NextResponse.json({
|
||||
error: 'Error sending email. Please try again later.'
|
||||
}, { status: 500 });
|
||||
return NextResponse.json({ error: 'Error sending email. Please try again later.' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ const NGSSection = () => {
|
||||
description: "Rapid sequencing of large genetic material be completed within a comparatively short duration, thereby yielding quick results."
|
||||
},
|
||||
{
|
||||
icon: "/images/homepage-1/service/Advantages-NGS-Icons-24.svg",
|
||||
icon: "/images/homepage-1/service/BioinformaticsAnalysis.svg",
|
||||
title: "Bioinformatics Analysis",
|
||||
description: "NGS produces vast amounts of data, supporting complex research through advanced bioinformatic analysis."
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ const CareerPage = () => {
|
||||
return (
|
||||
<div className="page-content contact-us">
|
||||
<CareerHero />
|
||||
<div className="h-6"></div>
|
||||
{/* <div className="h-2"></div> */}
|
||||
<CareerSection />
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -4,7 +4,7 @@ import CareerInfo from './CareerInfo';
|
||||
|
||||
const CareerSection = () => {
|
||||
return (
|
||||
<section className="py-10 md:py-16 lg:py-6">
|
||||
<section className="py-10 md:py-16 lg:py-2">
|
||||
<div className="container mx-auto max-w-none px-4">
|
||||
<div className="flex flex-col lg:flex-row gap-6">
|
||||
<CareerInfo />
|
||||
|
||||
@ -7,7 +7,7 @@ const ContactPage = () => {
|
||||
return (
|
||||
<div className="page-content contact-us">
|
||||
<PageTitle />
|
||||
<div className="h-6"></div>
|
||||
{/* <div className="h-6"></div> */}
|
||||
<ContactSection />
|
||||
<ContactMap />
|
||||
</div>
|
||||
|
||||
@ -39,7 +39,7 @@ const Footer = () => {
|
||||
</address>
|
||||
|
||||
{/* Social Links */}
|
||||
<div className="flex space-x-4 mt-8">
|
||||
<div className="flex mt-8">
|
||||
<a
|
||||
href="#"
|
||||
target="_blank"
|
||||
@ -136,7 +136,7 @@ const Footer = () => {
|
||||
<div className="container mx-auto px-4 py-4">
|
||||
<div className="flex flex-col md:flex-row justify-between items-center text-sm">
|
||||
<p>
|
||||
Copyright © 2024 <span className="text-gray-800 font-medium">Operify</span> All Rights Reserved.
|
||||
Copyright © 2025 <span className="text-gray-800 font-medium">Operify</span> All Rights Reserved.
|
||||
</p>
|
||||
<ul className="flex space-x-6 mt-3 md:mt-0">
|
||||
<li><Link href="#" className="hover:text-gray-800 transition-colors">Privacy Policy</Link></li>
|
||||
|
||||
@ -142,8 +142,8 @@ const ShippingTemperatureTable = () => {
|
||||
<table className="w-full border-collapse border border-gray-300 text-sm">
|
||||
<colgroup>
|
||||
<col style={{width: '25%'}} />
|
||||
<col style={{width: '25%'}} />
|
||||
<col style={{width: '50%'}} />
|
||||
<col style={{width: '40%'}} />
|
||||
<col style={{width: '35%'}} />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr className="bg-teal-50">
|
||||
|
||||
@ -8,70 +8,29 @@ import SampleDetailsSection from './SampleDetailsSection';
|
||||
|
||||
const SampleFormContainer = () => {
|
||||
const [formData, setFormData] = useState({
|
||||
// Customer Information
|
||||
Principal_Investigator: '',
|
||||
Email: '',
|
||||
Company_Institution: '',
|
||||
Contact_Number: '',
|
||||
Address: '',
|
||||
City: '',
|
||||
State: '',
|
||||
Pin: '',
|
||||
Secondary_Contact: '',
|
||||
Secondary_Email: '',
|
||||
Secondary_Company_Institution: '',
|
||||
Secondary_Contact_Number: '',
|
||||
|
||||
// Sample Information
|
||||
Project_Title: '',
|
||||
Number_of_Samples: '',
|
||||
Sample_Type: '',
|
||||
Sample_Type_Other: '',
|
||||
Sample_Source: '',
|
||||
Sample_Source_Other: '',
|
||||
Pathogenicity: '',
|
||||
Sample_Remarks: '',
|
||||
|
||||
// Service Information
|
||||
Service_Requested: '',
|
||||
Service_Requested_Other: '',
|
||||
Type_of_Library: '',
|
||||
Type_of_Library_Other: '',
|
||||
Required_Library_Size: '',
|
||||
Required_Library_Size_Other: '',
|
||||
Index_Information: '',
|
||||
Kit_Information: '',
|
||||
Sequencing_Platform: '',
|
||||
Sequencing_Platform_Other: '',
|
||||
Sequencing_Read_Length: '',
|
||||
Sequencing_Read_Length_Other: '',
|
||||
Total_Data_Requirement: '',
|
||||
Service_Remarks: '',
|
||||
|
||||
// Bioinformatics Information
|
||||
Analysis_Requested: '',
|
||||
Analysis_Details: '',
|
||||
Reference_Genome_Available: '',
|
||||
Genome_Size: '',
|
||||
Special_Consideration: '',
|
||||
Principal_Investigator: '', Email: '', Company_Institution: '', Contact_Number: '',
|
||||
Address: '', City: '', State: '', Pin: '', Secondary_Contact: '', Secondary_Email: '',
|
||||
Secondary_Company_Institution: '', Secondary_Contact_Number: '', Project_Title: '',
|
||||
Number_of_Samples: '', Sample_Type: '', Sample_Type_Other: '', Sample_Source: '',
|
||||
Sample_Source_Other: '', Pathogenicity: '', Sample_Remarks: '', Service_Requested: '',
|
||||
Service_Requested_Other: '', Type_of_Library: '', Type_of_Library_Other: '',
|
||||
Required_Library_Size: '', Required_Library_Size_Other: '', Index_Information: '',
|
||||
Kit_Information: '', Sequencing_Platform: '', Sequencing_Platform_Other: '',
|
||||
Sequencing_Read_Length: '', Sequencing_Read_Length_Other: '', Total_Data_Requirement: '',
|
||||
Service_Remarks: '', Analysis_Requested: '', Analysis_Details: '',
|
||||
Reference_Genome_Available: '', Genome_Size: '', Special_Consideration: ''
|
||||
});
|
||||
|
||||
const [sampleDetails, setSampleDetails] = useState([
|
||||
{
|
||||
Serial_Number: '',
|
||||
Sample_Name: '',
|
||||
Storage_Temp: '',
|
||||
Preservative_Reagent: '',
|
||||
Temp_Information: '',
|
||||
Comments: ''
|
||||
}
|
||||
]);
|
||||
const [sampleDetails, setSampleDetails] = useState([{
|
||||
Serial_Number: '', Sample_Name: '', Storage_Temp: '',
|
||||
Preservative_Reagent: '', Temp_Information: '', Comments: ''
|
||||
}]);
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [message, setMessage] = useState('');
|
||||
const [showSuccessModal, setShowSuccessModal] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Check for Excel data in sessionStorage
|
||||
const excelData = sessionStorage.getItem('excelData');
|
||||
const uploadedFileName = sessionStorage.getItem('uploadedFileName');
|
||||
|
||||
@ -79,11 +38,8 @@ const SampleFormContainer = () => {
|
||||
try {
|
||||
const jsonData = JSON.parse(excelData);
|
||||
autoFillForm(jsonData);
|
||||
|
||||
// Clear stored data
|
||||
sessionStorage.removeItem('excelData');
|
||||
sessionStorage.removeItem('uploadedFileName');
|
||||
|
||||
setMessage(`Form auto-filled from uploaded file: ${uploadedFileName}`);
|
||||
} catch (error) {
|
||||
console.error('Error parsing Excel data:', error);
|
||||
@ -93,14 +49,10 @@ const SampleFormContainer = () => {
|
||||
|
||||
const autoFillForm = (jsonData) => {
|
||||
if (jsonData.length === 0) return;
|
||||
|
||||
const data = jsonData[0];
|
||||
const newFormData = { ...formData };
|
||||
|
||||
// Helper function to safely get value
|
||||
const getValue = (key) => data[key] ? data[key].toString().trim() : '';
|
||||
|
||||
// Customer Information
|
||||
newFormData.Principal_Investigator = getValue('Principal Investigator');
|
||||
newFormData.Email = getValue('Email');
|
||||
newFormData.Company_Institution = getValue('Company/Institution');
|
||||
@ -114,7 +66,6 @@ const SampleFormContainer = () => {
|
||||
newFormData.Secondary_Company_Institution = getValue('Secondary Company/Institution');
|
||||
newFormData.Secondary_Contact_Number = getValue('Secondary Contact Number');
|
||||
|
||||
// Sample Information
|
||||
newFormData.Project_Title = getValue('Project Title');
|
||||
newFormData.Number_of_Samples = getValue('Number of Samples');
|
||||
newFormData.Sample_Type = getValue('Sample Type');
|
||||
@ -124,7 +75,6 @@ const SampleFormContainer = () => {
|
||||
newFormData.Pathogenicity = getValue('Pathogenicity');
|
||||
newFormData.Sample_Remarks = getValue('Sample Remarks');
|
||||
|
||||
// Service Information
|
||||
newFormData.Service_Requested = getValue('Service Requested');
|
||||
newFormData.Service_Requested_Other = getValue('Service Requested Other');
|
||||
newFormData.Type_of_Library = getValue('Type of Library');
|
||||
@ -140,7 +90,6 @@ const SampleFormContainer = () => {
|
||||
newFormData.Total_Data_Requirement = getValue('Total Data Requirement');
|
||||
newFormData.Service_Remarks = getValue('Service Remarks');
|
||||
|
||||
// Bioinformatics Information
|
||||
newFormData.Analysis_Requested = getValue('Analysis Requested');
|
||||
newFormData.Analysis_Details = getValue('Analysis Details');
|
||||
newFormData.Reference_Genome_Available = getValue('Reference Genome Available');
|
||||
@ -149,21 +98,20 @@ const SampleFormContainer = () => {
|
||||
|
||||
setFormData(newFormData);
|
||||
|
||||
// Handle Sample Details
|
||||
const sampleDetailsData = jsonData.filter(row =>
|
||||
row['Serial Number'] || row['Sample Name'] ||
|
||||
row['Storage Temp'] || row['Preservative Reagent'] ||
|
||||
const sampleDetailsData = jsonData.filter(row =>
|
||||
row['Serial Number'] || row['Sample Name'] ||
|
||||
row['Storage Temp'] || row['Preservative Reagent'] ||
|
||||
row['Temp Information'] || row['Comments']
|
||||
);
|
||||
|
||||
if (sampleDetailsData.length > 0) {
|
||||
const newSampleDetails = sampleDetailsData.map(sample => ({
|
||||
Serial_Number: getValue('Serial Number'),
|
||||
Sample_Name: getValue('Sample Name'),
|
||||
Storage_Temp: getValue('Storage Temp'),
|
||||
Preservative_Reagent: getValue('Preservative Reagent'),
|
||||
Temp_Information: getValue('Temp Information'),
|
||||
Comments: getValue('Comments')
|
||||
Serial_Number: sample['Serial Number'] || '',
|
||||
Sample_Name: sample['Sample Name'] || '',
|
||||
Storage_Temp: sample['Storage Temp'] || '',
|
||||
Preservative_Reagent: sample['Preservative Reagent'] || '',
|
||||
Temp_Information: sample['Temp Information'] || '',
|
||||
Comments: sample['Comments'] || ''
|
||||
}));
|
||||
setSampleDetails(newSampleDetails);
|
||||
}
|
||||
@ -179,37 +127,28 @@ const SampleFormContainer = () => {
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
setMessage(''); // Clear previous messages
|
||||
|
||||
setMessage('');
|
||||
try {
|
||||
const formDataToSend = new FormData();
|
||||
|
||||
// Add form data
|
||||
Object.keys(formData).forEach(key => {
|
||||
if (formData[key]) {
|
||||
formDataToSend.append(key, formData[key]);
|
||||
}
|
||||
});
|
||||
|
||||
// Add sample details as JSON string
|
||||
formDataToSend.append('sample_details', JSON.stringify(sampleDetails));
|
||||
formDataToSend.append('form_type', 'sample');
|
||||
|
||||
console.log('Submitting form data:', formData);
|
||||
console.log('Sample details:', sampleDetails);
|
||||
|
||||
const response = await fetch('/api/forms', {
|
||||
method: 'POST',
|
||||
body: formDataToSend,
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
console.log('API Response:', result);
|
||||
|
||||
|
||||
if (response.ok) {
|
||||
setMessage(result.message);
|
||||
|
||||
// Reset form after successful submission
|
||||
setShowSuccessModal(true); // show modal instead of green alert
|
||||
|
||||
setFormData({
|
||||
Principal_Investigator: '', Email: '', Company_Institution: '', Contact_Number: '',
|
||||
Address: '', City: '', State: '', Pin: '', Secondary_Contact: '', Secondary_Email: '',
|
||||
@ -223,7 +162,6 @@ const SampleFormContainer = () => {
|
||||
Service_Remarks: '', Analysis_Requested: '', Analysis_Details: '',
|
||||
Reference_Genome_Available: '', Genome_Size: '', Special_Consideration: ''
|
||||
});
|
||||
|
||||
setSampleDetails([{
|
||||
Serial_Number: '', Sample_Name: '', Storage_Temp: '',
|
||||
Preservative_Reagent: '', Temp_Information: '', Comments: ''
|
||||
@ -231,7 +169,6 @@ const SampleFormContainer = () => {
|
||||
} else {
|
||||
setMessage('Error: ' + (result.error || 'Form submission failed'));
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error submitting form:', error);
|
||||
setMessage('Error: Network error. Please check your connection and try again.');
|
||||
@ -244,41 +181,22 @@ const SampleFormContainer = () => {
|
||||
<div className="bg-teal-50 min-h-screen py-8">
|
||||
<div className="max-w-4xl mx-auto bg-teal-50 shadow-lg border border-gray-300 font-arial text-xs">
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* Show message if exists */}
|
||||
{message && (
|
||||
|
||||
{/* Only show red alert for errors */}
|
||||
{message && message.includes('Error') && (
|
||||
<div className="mx-6 mt-6">
|
||||
<div className={`p-4 rounded ${message.includes('Error') ? 'bg-red-100 text-red-800' : 'bg-green-100 text-green-800'}`}>
|
||||
<div className="p-4 rounded bg-red-100 text-red-800">
|
||||
{message}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<CustomerInfoSection
|
||||
formData={formData}
|
||||
onInputChange={handleInputChange}
|
||||
/>
|
||||
|
||||
<SampleInfoSection
|
||||
formData={formData}
|
||||
onInputChange={handleInputChange}
|
||||
/>
|
||||
|
||||
<ServiceInfoSection
|
||||
formData={formData}
|
||||
onInputChange={handleInputChange}
|
||||
/>
|
||||
|
||||
<BioinformaticsSection
|
||||
formData={formData}
|
||||
onInputChange={handleInputChange}
|
||||
/>
|
||||
|
||||
<SampleDetailsSection
|
||||
sampleDetails={sampleDetails}
|
||||
setSampleDetails={setSampleDetails}
|
||||
/>
|
||||
<CustomerInfoSection formData={formData} onInputChange={handleInputChange} />
|
||||
<SampleInfoSection formData={formData} onInputChange={handleInputChange} />
|
||||
<ServiceInfoSection formData={formData} onInputChange={handleInputChange} />
|
||||
<BioinformaticsSection formData={formData} onInputChange={handleInputChange} />
|
||||
<SampleDetailsSection sampleDetails={sampleDetails} setSampleDetails={setSampleDetails} />
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="text-center py-6">
|
||||
<button
|
||||
type="submit"
|
||||
@ -290,8 +208,50 @@ const SampleFormContainer = () => {
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* Success Modal */}
|
||||
{/* Success Modal */}
|
||||
{showSuccessModal && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white rounded-lg shadow-lg p-6 max-w-sm w-full text-center animate-pulse">
|
||||
{/* Animated Check Circle */}
|
||||
<div className="flex justify-center mb-4">
|
||||
<div className="relative">
|
||||
{/* Outer ring animation */}
|
||||
<div className="w-20 h-20 border-4 border-green-200 rounded-full animate-ping absolute"></div>
|
||||
<div className="w-16 h-16 bg-green-500 rounded-full flex items-center justify-center animate-bounce relative z-10">
|
||||
{/* Checkmark */}
|
||||
<svg
|
||||
className="w-10 h-10 text-white animate-pulse"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="4"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className="text-lg font-semibold text-green-700 mb-4 animate-pulse">Submitted Successfully!</h2>
|
||||
<p className="text-gray-700 mb-6">{message}</p>
|
||||
<button
|
||||
onClick={() => setShowSuccessModal(false)}
|
||||
className="bg-teal-600 hover:bg-teal-700 text-white py-2 px-4 rounded transition-all duration-200 transform hover:scale-105"
|
||||
>
|
||||
OK
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SampleFormContainer;
|
||||
export default SampleFormContainer;
|
||||
|
||||
@ -1,96 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const EnrichmentPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Alignment to Reference Genome"
|
||||
],
|
||||
rightSteps = [
|
||||
"Downstream Advanced Analysis",
|
||||
"Annotation",
|
||||
"Variants Calling - SNVs, Indels, CNVs",
|
||||
"Mark Duplicates and Post-Processing"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/resequencing.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-5xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block sm:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tablet and Desktop Layout - Two Columns */}
|
||||
<div className="hidden sm:block">
|
||||
<div className="grid grid-cols-2 gap-4 sm:gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
||||
<div className="absolute bottom-2 sm:bottom-4 lg:bottom-[0.7rem] left-1/2 transform -translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,126 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const EpigenomicsPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Aligned to Reference Genome"
|
||||
],
|
||||
middleSteps = [
|
||||
"Downstream Advanced Analysis",
|
||||
"DMR Annotation",
|
||||
"DMR Identification",
|
||||
"Peak Calling"
|
||||
],
|
||||
rightSteps = [
|
||||
"Distribution in genes & repeats",
|
||||
"Methylated Distribution",
|
||||
"Motif Identification",
|
||||
"Relationship with gene expression",
|
||||
"Go clustering",
|
||||
"Pathway analysis"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/epigenomics.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...middleSteps, ...rightSteps];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-7xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block lg:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Layout - Three Columns */}
|
||||
<div className="hidden lg:block">
|
||||
<div className="grid grid-cols-3 gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full max-w-76 text-center border ${cardClassName}`} style={{maxWidth: '19rem'}}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Middle Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{middleSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full max-w-76 text-center border ${cardClassName}`} style={{maxWidth: '19rem'}}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < middleSteps.length - 1 && (
|
||||
<ArrowUp className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<div className={`${cardColor} rounded-lg p-12 w-full max-w-76 text-center border ${cardClassName}`} style={{maxWidth: '19rem'}}>
|
||||
<div className="space-y-6">
|
||||
{rightSteps.map((step, index) => (
|
||||
<div key={index} className={`text-sm font-medium ${textColor}`}>
|
||||
{step}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrows */}
|
||||
{/* Arrow from Aligned to Reference Genome to Peak Calling */}
|
||||
<div className="absolute bottom-4 left-1/3 transform -translate-x-1/2">
|
||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
{/* Arrow from DMR Annotation to right box */}
|
||||
<div className="absolute top-28 left-2/3 transform -translate-x-1/2">
|
||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
||||
</div>
|
||||
{/* Arrow from Peak Calling to right box */}
|
||||
<div className="absolute bottom-4 left-2/3 transform -translate-x-1/2">
|
||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,96 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const GenomeMappingPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Alignment to Reference Genome"
|
||||
],
|
||||
rightSteps = [
|
||||
"Evolutionary Analysis",
|
||||
"Annotation",
|
||||
"Variants Calling - structural variants and genomic rearrangements",
|
||||
"Post-Processing"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/genoemapping.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-5xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block sm:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tablet and Desktop Layout - Two Columns */}
|
||||
<div className="hidden sm:block">
|
||||
<div className="grid grid-cols-2 gap-4 sm:gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
||||
<div className="absolute bottom-2 sm:bottom-4 lg:bottom-[0.7rem] left-1/2 transform -translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,124 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const MetagenomicsPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftColumn = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Alignment to Host Genome"
|
||||
],
|
||||
middleColumn = [
|
||||
"Assembly Validation",
|
||||
"Secondary Assembly (Scaffolds)",
|
||||
"Primary Assembly (Contigs) using Unaligned Data",
|
||||
"Remove Aligned reads to Host Genome and Retain only Unaligned Reads"
|
||||
],
|
||||
rightColumn = [
|
||||
"Gene Prediction and Gene Annotation",
|
||||
"Downstream Advanced Analysis"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/metagenomics.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine all steps for mobile layout
|
||||
const mobileSteps = [
|
||||
...leftColumn,
|
||||
...middleColumn.slice().reverse(),
|
||||
...rightColumn
|
||||
];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-600 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-6xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block lg:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Layout - Three Columns */}
|
||||
<div className="hidden lg:block">
|
||||
<div className="grid grid-cols-3 gap-6 lg:gap-10">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{leftColumn.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftColumn.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Middle Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{middleColumn.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < middleColumn.length - 1 && (
|
||||
<ArrowUp className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{rightColumn.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightColumn.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrows */}
|
||||
{/* Arrow from left to middle column */}
|
||||
<div className="absolute bottom-8 left-1/3 transform -translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
|
||||
{/* Arrow from middle to right column */}
|
||||
<div className="absolute top-4 right-1/3 transform translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,96 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const SingleCellPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Alignment to Reference Genome"
|
||||
],
|
||||
rightSteps = [
|
||||
"Evolutionary Analysis",
|
||||
"Annotation",
|
||||
"Variants Calling - SNVs, Indels, CNVs",
|
||||
"Mark Duplicates and Post-Processing"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/singlecell.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-5xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block sm:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tablet and Desktop Layout - Two Columns */}
|
||||
<div className="hidden sm:block">
|
||||
<div className="grid grid-cols-2 gap-4 sm:gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
||||
<div className="absolute bottom-2 sm:bottom-4 lg:bottom-[0.7rem] left-1/2 transform -translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,96 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const WGSDeNovoPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Primary Assembly (Contigs)"
|
||||
],
|
||||
rightSteps = [
|
||||
"Downstream Advanced Analysis",
|
||||
"Gene Prediction and Gene Annotation",
|
||||
"Assembly Validation",
|
||||
"Secondary Assembly (Scaffolds)"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/denovo.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-5xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block sm:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tablet and Desktop Layout - Two Columns */}
|
||||
<div className="hidden sm:block">
|
||||
<div className="grid grid-cols-2 gap-4 sm:gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
||||
<div className="absolute bottom-2 sm:bottom-4 lg:bottom-[0.7rem] left-1/2 transform -translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,96 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const WGSResequencingPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Alignment to Reference Genome"
|
||||
],
|
||||
rightSteps = [
|
||||
"Downstream Advanced Analysis",
|
||||
"Annotation",
|
||||
"Variants Calling - SNVs, Indels, CNVs",
|
||||
"Mark Duplicates and Post-Processing"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/resequencing.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-5xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block sm:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tablet and Desktop Layout - Two Columns */}
|
||||
<div className="hidden sm:block">
|
||||
<div className="grid grid-cols-2 gap-4 sm:gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
||||
<div className="absolute bottom-2 sm:bottom-4 lg:bottom-[0.7rem] left-1/2 transform -translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,130 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const CircularRNAPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Alignment to Reference Genome"
|
||||
],
|
||||
rightSteps = [
|
||||
"Downstream Advanced Analysis",
|
||||
"Circular RNA Identification",
|
||||
"Circular RNA Prediction",
|
||||
"Back Splicing Junction Reads"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/circularrna.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-5xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block sm:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tablet and Desktop Layout - Two Columns */}
|
||||
<div className="hidden sm:block">
|
||||
<div className="grid grid-cols-2 gap-4 sm:gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-2 sm:space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 sm:p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs sm:text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-5 h-5 sm:w-6 sm:h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Custom arrows from "Alignment to Reference Genome" */}
|
||||
<div className="absolute bottom-12 sm:bottom-16 lg:bottom-[2rem] left-1/2 transform -translate-x-1/2">
|
||||
<div className="relative w-0 h-0">
|
||||
|
||||
{/* Arrow 1: Straight horizontal to "Back Splicing Junction Reads" (Unmapped Reads) */}
|
||||
<div className="absolute top-0 left-0">
|
||||
<div className="relative">
|
||||
{/* Horizontal line */}
|
||||
<div className="w-16 sm:w-20 lg:w-28 h-0.5 bg-gray-600"></div>
|
||||
{/* Arrowhead */}
|
||||
<div className="absolute right-0 -top-1 w-2 h-2 border-r-2 border-t-2 border-gray-600 rotate-45"></div>
|
||||
{/* Label */}
|
||||
<div className="absolute top-2 left-4 sm:left-6 lg:left-10 text-xs text-gray-700 font-medium whitespace-nowrap">
|
||||
Unmapped Reads
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Arrow 2: Diagonal upward to "Circular RNA Prediction" (Mapped Reads) */}
|
||||
<div className="absolute top-0 left-0">
|
||||
<div className="relative">
|
||||
{/* Diagonal line going up and right */}
|
||||
<div className="absolute origin-left w-20 sm:w-24 lg:w-32 h-0.5 bg-gray-600 transform -rotate-45"></div>
|
||||
{/* Arrowhead positioned at the end of diagonal line */}
|
||||
<div className="absolute w-2 h-2 border-r-2 border-t-2 border-gray-600 transform rotate-0"
|
||||
style={{
|
||||
left: 'calc(20 * 0.25rem * 0.707 - 4px)', // cos(45deg) ≈ 0.707
|
||||
top: 'calc(-20 * 0.25rem * 0.707 - 4px)' // -sin(45deg) ≈ -0.707
|
||||
}}></div>
|
||||
{/* Label */}
|
||||
<div className="absolute -top-8 left-6 sm:left-8 lg:left-12 text-xs text-gray-700 font-medium whitespace-nowrap">
|
||||
Mapped Reads
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,123 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const DegradomeSequencingPipeline = ({
|
||||
title = "Degradome Sequencing",
|
||||
title = "Bioinformatics Pipeline",
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/degradomerna.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-blue-200",
|
||||
textColor = "text-gray-800",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
const leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Alignment to Reference Genome"
|
||||
];
|
||||
|
||||
const rightSteps = [
|
||||
"Related miRNA Identification",
|
||||
"mRNAs Degradome Sites",
|
||||
"Identify Target mRNAs",
|
||||
"Retain mRNA data Remove rRNA, tRNA and other RNA"
|
||||
];
|
||||
|
||||
const middleSteps = [
|
||||
"Functional Analysis"
|
||||
];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-6xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block lg:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{[...leftSteps, ...rightSteps.slice().reverse(), ...middleSteps].map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length + rightSteps.length + middleSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Layout - Complex Flow */}
|
||||
<div className="hidden lg:block">
|
||||
<div className="grid grid-cols-3 gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Middle Column */}
|
||||
<div className="flex flex-col items-center justify-center space-y-3">
|
||||
{middleSteps.map((step, index) => (
|
||||
<div key={index} className={`${cardColor} rounded-lg p-4 w-full max-w-60 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full max-w-80 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrow from left to right (after alignment) */}
|
||||
<div className="absolute bottom-4 left-1/3 transform -translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
|
||||
{/* Bidirectional arrows between middle and right columns */}
|
||||
<div className="absolute top-1/2 right-1/3 transform translate-x-1/2 -translate-y-1/2 flex flex-col items-center space-y-2">
|
||||
<ArrowUp className={`w-6 h-6 ${arrowColor}`} />
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
</div>
|
||||
|
||||
{/* Additional arrows for the circular flow in right column */}
|
||||
<div className="absolute top-1/4 right-6 flex items-center justify-center">
|
||||
<ArrowUp className={`w-5 h-5 ${arrowColor}`} />
|
||||
</div>
|
||||
|
||||
<div className="absolute top-2/3 right-6 flex items-center justify-center">
|
||||
<ArrowUp className={`w-5 h-5 ${arrowColor}`} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,127 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const IsoformPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Build Similarity Graph and Polishing"
|
||||
],
|
||||
rightSteps = [
|
||||
"Downstream Analysis (Fusion Analysis, Splicing Analysis)",
|
||||
"Transcript Annotation and Classification",
|
||||
"Sequencing Merge and Redundancy Removal",
|
||||
"Alignment to Reference Genome"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/isoseqrna.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-5xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block sm:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Layout - Two Columns */}
|
||||
<div className="hidden sm:block">
|
||||
<div className="grid grid-cols-2 gap-4 sm:gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`} style={{maxWidth: '19rem'}}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`} style={{maxWidth: '19rem'}}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Diagonal Arrow from High Quality Sequencing Data to Alignment to Reference Genome */}
|
||||
<div className="absolute top-80 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
||||
<svg
|
||||
width="180"
|
||||
height="60"
|
||||
viewBox="0 0 180 60"
|
||||
className={arrowColor}
|
||||
style={{transform: 'rotate(20deg)'}}
|
||||
>
|
||||
<defs>
|
||||
<marker
|
||||
id="arrowhead"
|
||||
markerWidth="10"
|
||||
markerHeight="7"
|
||||
refX="9"
|
||||
refY="3.5"
|
||||
orient="auto"
|
||||
>
|
||||
<polygon
|
||||
points="0 0, 10 3.5, 0 7"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</marker>
|
||||
</defs>
|
||||
<line
|
||||
x1="10"
|
||||
y1="10"
|
||||
x2="170"
|
||||
y2="50"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
markerEnd="url(#arrowhead)"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,28 +1,51 @@
|
||||
// app/rna-sequencing/lncrna-sequencing/components/LncRNABioinformatics.jsx
|
||||
import React from 'react';
|
||||
|
||||
const LncRNABioinformatics = () => {
|
||||
const LncRNABioinformatics = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/totalrna.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
return (
|
||||
<section className="py-8 lg:py-12 bg-gray-50">
|
||||
<div className="container mx-auto max-w-none px-4 lg:px-6">
|
||||
<h2 className="text-2xl lg:text-3xl text-gray-700 text-left pb-2 mb-6 lg:mb-6">
|
||||
Bioinformatics Pipeline
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Image */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-6 lg:p-8">
|
||||
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<img
|
||||
src="/images/lncrna-bioinformatics-pipeline.jpg"
|
||||
alt="lncRNA Sequencing Bioinformatics Pipeline Workflow"
|
||||
className="max-w-full h-auto rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Pipeline Description */}
|
||||
<div className="mt-6 text-center">
|
||||
<p className="text-gray-600 text-sm lg:text-base">
|
||||
lncRNA sequencing bioinformatics pipeline for long non-coding RNA analysis and expression profiling
|
||||
</p>
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -30,4 +53,4 @@ const LncRNABioinformatics = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default LncRNABioinformatics
|
||||
export default LncRNABioinformatics;
|
||||
@ -1,188 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const MetatranscriptomicsPipeline = ({
|
||||
title = "Metatranscriptomics",
|
||||
title = "Bioinformatics Pipeline",
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/metatranscriptomicsrna.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-blue-200",
|
||||
textColor = "text-blue-800",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
const topSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Retain mRNA reads and remove rRNA Reads"
|
||||
];
|
||||
|
||||
const bottomLeftSteps = [
|
||||
"Reference Genome Alignment",
|
||||
"Gene Expression Analysis",
|
||||
"Differential Analysis"
|
||||
];
|
||||
|
||||
const bottomCenterSteps = [
|
||||
"Transcript Assembly",
|
||||
"Structural Identification",
|
||||
"SNPs, SSRs Analysis eQTLs Analysis"
|
||||
];
|
||||
|
||||
const bottomRightSteps = [
|
||||
"Functional Annotation",
|
||||
"Statistical Analysis"
|
||||
];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-6xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block lg:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{topSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < topSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
{/* Bottom sections for mobile */}
|
||||
<div className="grid grid-cols-1 gap-4 w-full mt-6">
|
||||
{bottomLeftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < bottomLeftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor} mx-auto`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
{bottomCenterSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < bottomCenterSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor} mx-auto`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
{bottomRightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < bottomRightSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor} mx-auto`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Layout */}
|
||||
<div className="hidden lg:block">
|
||||
{/* Top vertical sequence */}
|
||||
<div className="flex flex-col items-center space-y-4 mb-8">
|
||||
{topSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-96 text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < topSteps.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
|
||||
{/* Branching arrows from "Retain mRNA reads and remove rRNA Reads" */}
|
||||
<div className="flex justify-center mb-8">
|
||||
<div className="relative">
|
||||
{/* Left branch arrow */}
|
||||
<div className="absolute -left-32 top-0">
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
</div>
|
||||
|
||||
{/* Right branch arrow */}
|
||||
<div className="absolute left-32 top-0">
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom three columns */}
|
||||
<div className="grid grid-cols-3 gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
{bottomLeftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < bottomLeftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Center Column */}
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
{bottomCenterSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < bottomCenterSteps.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
{bottomRightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < bottomRightSteps.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal arrows connecting bottom sections */}
|
||||
<div className="absolute bottom-4 left-1/3 transform -translate-x-1/2">
|
||||
<ArrowRight className={`w-6 h-6 ${arrowColor}`} />
|
||||
</div>
|
||||
<div className="absolute bottom-4 right-1/3 transform translate-x-1/2">
|
||||
<ArrowRight className={`w-6 h-6 ${arrowColor}`} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,98 +1,49 @@
|
||||
import React from 'react';
|
||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
||||
|
||||
const SRNABioinformatics = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
leftSteps = [
|
||||
"Raw Sequencing Data (fastq files)",
|
||||
"Quality Control and Preprocessing of Data",
|
||||
"High Quality Sequencing Data (fastq file)",
|
||||
"Blast Against mRNA, Rfam and RepBase",
|
||||
"Retained data with no annotation and remove data annotated with mRNA, Rfam and RepBase"
|
||||
],
|
||||
rightSteps = [
|
||||
"Downstream Advanced Analysis",
|
||||
"Identification of known and Novel microRNA",
|
||||
"Hairpin Prediction",
|
||||
"Aligned to Genome",
|
||||
"Aligned to Genome"
|
||||
],
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/smallrna.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
cardColor = "bg-gray-300",
|
||||
textColor = "text-teal-600",
|
||||
arrowColor = "text-gray-600",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
cardClassName = "",
|
||||
titleClassName = ""
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
// Combine steps for mobile layout
|
||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
||||
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className="container mx-auto max-w-none px-3 sm:px-4 lg:px-6">
|
||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* Pipeline Flowchart */}
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-5xl">
|
||||
<div className="relative">
|
||||
{/* Mobile Layout - Single Column */}
|
||||
<div className="block sm:hidden">
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{mobileSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < mobileSteps.length - 1 && (
|
||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Desktop Layout - Two Columns */}
|
||||
<div className="hidden sm:block">
|
||||
<div className="grid grid-cols-2 gap-4 sm:gap-6 lg:gap-8">
|
||||
{/* Left Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{leftSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`} style={{maxWidth: '19rem'}}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < leftSteps.length - 1 && (
|
||||
<ArrowDown className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Right Column */}
|
||||
<div className="flex flex-col items-center space-y-3">
|
||||
{rightSteps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className={`${cardColor} rounded-lg p-4 w-full text-center border ${cardClassName}`} style={{maxWidth: '19rem'}}>
|
||||
<h3 className={`text-sm font-medium ${textColor}`}>{step}</h3>
|
||||
</div>
|
||||
{index < rightSteps.length - 1 && (
|
||||
<ArrowUp className={`w-6 h-6 ${arrowColor}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Horizontal Arrow from Transcript Assembly to Transcript Assembly Validation */}
|
||||
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex items-center justify-center">
|
||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
import React from 'react';
|
||||
|
||||
const WTSPipeline = ({
|
||||
title = "Bioinformatics Pipeline",
|
||||
svgContent = null, // Pass your SVG content here as JSX
|
||||
svgUrl = "/images/flowchart/totalrna.svg",
|
||||
backgroundColor = "bg-gray-50",
|
||||
textColor = "text-gray-700",
|
||||
className = "",
|
||||
titleClassName = "",
|
||||
svgClassName = "",
|
||||
containerClassName = ""
|
||||
}) => {
|
||||
return (
|
||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
{/* SVG Flowchart Container */}
|
||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-full max-w-6xl">
|
||||
{/* SVG Container with responsive sizing */}
|
||||
<div className={`w-full ${svgClassName}`}>
|
||||
{svgUrl ? (
|
||||
// If SVG URL/path is provided
|
||||
<img
|
||||
src={svgUrl}
|
||||
alt="Flowchart diagram"
|
||||
className="w-full h-auto object-contain"
|
||||
/>
|
||||
) : svgContent ? (
|
||||
// If SVG content is provided as JSX
|
||||
<div className="w-full">
|
||||
<div className="w-full">
|
||||
{svgContent}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
// Fallback message
|
||||
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||
<p>Please provide SVG content or URL</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default WTSPipeline;
|
||||
@ -2,6 +2,7 @@
|
||||
import TitleBar from '../../components/shared/TitleBar';
|
||||
import WTSIntroduction from './components/WTSIntroduction';
|
||||
import WTSAdvantages from './components/WTSAdvantages';
|
||||
import WTSPipeline from './components/WTSPipeline';
|
||||
import WTSApplications from './components/WTSApplications';
|
||||
import WTSSpecifications from './components/WTSSpecifications';
|
||||
import PageLayout from '../../components/Layout/PageLayout';
|
||||
@ -21,6 +22,7 @@ export default function WholeTranscriptomeSequencingPage() {
|
||||
/>
|
||||
<WTSIntroduction />
|
||||
<WTSAdvantages />
|
||||
<WTSPipeline/>
|
||||
<WTSApplications />
|
||||
<WTSSpecifications />
|
||||
</PageLayout>
|
||||
|
||||
10
package-lock.json
generated
@ -8,6 +8,7 @@
|
||||
"name": "nextjs",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"lucide-react": "^0.525.0",
|
||||
"next": "^15.2.0",
|
||||
"nodemailer": "^7.0.3",
|
||||
@ -214,6 +215,15 @@
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@heroicons/react": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz",
|
||||
"integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">= 16 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"lucide-react": "^0.525.0",
|
||||
"next": "^15.2.0",
|
||||
"nodemailer": "^7.0.3",
|
||||
|
||||
36
public/images/flowchart/circularrna.svg
Normal file
|
After Width: | Height: | Size: 224 KiB |
38
public/images/flowchart/degradomerna.svg
Normal file
|
After Width: | Height: | Size: 217 KiB |
25
public/images/flowchart/denovo.svg
Normal file
|
After Width: | Height: | Size: 202 KiB |
38
public/images/flowchart/epigenomics.svg
Normal file
|
After Width: | Height: | Size: 274 KiB |
32
public/images/flowchart/genoemapping.svg
Normal file
|
After Width: | Height: | Size: 204 KiB |
32
public/images/flowchart/isoseqrna.svg
Normal file
|
After Width: | Height: | Size: 249 KiB |
40
public/images/flowchart/metagenomics.svg
Normal file
|
After Width: | Height: | Size: 295 KiB |
51
public/images/flowchart/metatranscriptomicsrna.svg
Normal file
|
After Width: | Height: | Size: 246 KiB |
40
public/images/flowchart/mrna.svg
Normal file
|
After Width: | Height: | Size: 222 KiB |
32
public/images/flowchart/resequencing.svg
Normal file
|
After Width: | Height: | Size: 205 KiB |
32
public/images/flowchart/singlecell.svg
Normal file
|
After Width: | Height: | Size: 196 KiB |
40
public/images/flowchart/singlecellrna.svg
Normal file
|
After Width: | Height: | Size: 257 KiB |
40
public/images/flowchart/smallrna.svg
Normal file
|
After Width: | Height: | Size: 282 KiB |
40
public/images/flowchart/totalrna.svg
Normal file
|
After Width: | Height: | Size: 274 KiB |
14
public/images/homepage-1/service/BioinformaticsAnalysis.svg
Normal file
|
After Width: | Height: | Size: 5.4 KiB |