Flowchart Updated
@ -30,21 +30,14 @@ const configs = {
|
|||||||
sample: {
|
sample: {
|
||||||
subject: 'SIF Form received for Project',
|
subject: 'SIF Form received for Project',
|
||||||
fields: [
|
fields: [
|
||||||
// Customer Information
|
|
||||||
'Principal_Investigator', 'Email', 'Company_Institution', 'Contact_Number', 'Address', 'City', 'State', 'Pin',
|
'Principal_Investigator', 'Email', 'Company_Institution', 'Contact_Number', 'Address', 'City', 'State', 'Pin',
|
||||||
'Secondary_Contact', 'Secondary_Email', 'Secondary_Company_Institution', 'Secondary_Contact_Number',
|
'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',
|
'Project_Title', 'Number_of_Samples', 'Sample_Type', 'Sample_Type_Other', 'Sample_Source', 'Sample_Source_Other',
|
||||||
'Pathogenicity', 'Sample_Remarks',
|
'Pathogenicity', 'Sample_Remarks',
|
||||||
|
|
||||||
// Service Information
|
|
||||||
'Service_Requested', 'Service_Requested_Other', 'Type_of_Library', 'Type_of_Library_Other',
|
'Service_Requested', 'Service_Requested_Other', 'Type_of_Library', 'Type_of_Library_Other',
|
||||||
'Required_Library_Size', 'Required_Library_Size_Other', 'Index_Information', 'Kit_Information',
|
'Required_Library_Size', 'Required_Library_Size_Other', 'Index_Information', 'Kit_Information',
|
||||||
'Sequencing_Platform', 'Sequencing_Platform_Other', 'Sequencing_Read_Length', 'Sequencing_Read_Length_Other',
|
'Sequencing_Platform', 'Sequencing_Platform_Other', 'Sequencing_Read_Length', 'Sequencing_Read_Length_Other',
|
||||||
'Total_Data_Requirement', 'Service_Remarks',
|
'Total_Data_Requirement', 'Service_Remarks',
|
||||||
|
|
||||||
// Bioinformatics Information
|
|
||||||
'Analysis_Requested', 'Analysis_Details', 'Reference_Genome_Available', 'Genome_Size', 'Special_Consideration'
|
'Analysis_Requested', 'Analysis_Details', 'Reference_Genome_Available', 'Genome_Size', 'Special_Consideration'
|
||||||
],
|
],
|
||||||
required: [
|
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
|
// Utility functions
|
||||||
function isValidEmail(email) {
|
function isValidEmail(email) {
|
||||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||||
@ -77,7 +88,6 @@ export async function GET() {
|
|||||||
|
|
||||||
export async function POST(request) {
|
export async function POST(request) {
|
||||||
try {
|
try {
|
||||||
// Parse form data
|
|
||||||
const formData = await request.formData();
|
const formData = await request.formData();
|
||||||
const data = {};
|
const data = {};
|
||||||
const files = {};
|
const files = {};
|
||||||
@ -92,7 +102,6 @@ export async function POST(request) {
|
|||||||
|
|
||||||
const form_type = data.form_type;
|
const form_type = data.form_type;
|
||||||
|
|
||||||
// Validate form type
|
|
||||||
if (!form_type || !configs[form_type]) {
|
if (!form_type || !configs[form_type]) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
error: 'Invalid form type: ' + (form_type || 'missing')
|
error: 'Invalid form type: ' + (form_type || 'missing')
|
||||||
@ -102,7 +111,6 @@ export async function POST(request) {
|
|||||||
const config = configs[form_type];
|
const config = configs[form_type];
|
||||||
const errors = [];
|
const errors = [];
|
||||||
|
|
||||||
// Validate required fields
|
|
||||||
for (const required_field of config.required) {
|
for (const required_field of config.required) {
|
||||||
if (!data[required_field] || String(data[required_field]).trim() === '') {
|
if (!data[required_field] || String(data[required_field]).trim() === '') {
|
||||||
errors.push(`The "${fieldName(required_field)}" field is required.`);
|
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') {
|
if (form_type === 'career') {
|
||||||
const fileField = config.file_field;
|
const fileField = config.file_field;
|
||||||
const uploadedFile = files[fileField];
|
const uploadedFile = files[fileField];
|
||||||
|
|
||||||
if (!uploadedFile || uploadedFile.size === 0) {
|
if (!uploadedFile || uploadedFile.size === 0) {
|
||||||
errors.push('Please upload your resume.');
|
errors.push('Please upload your resume.');
|
||||||
} else {
|
} else {
|
||||||
const allowedExtensions = ['pdf', 'doc', 'docx'];
|
const allowedExtensions = ['pdf', 'doc', 'docx'];
|
||||||
const fileName = uploadedFile.name.toLowerCase();
|
const fileExtension = uploadedFile.name.toLowerCase().split('.').pop();
|
||||||
const fileExtension = fileName.split('.').pop();
|
|
||||||
|
|
||||||
if (!allowedExtensions.includes(fileExtension)) {
|
if (!allowedExtensions.includes(fileExtension)) {
|
||||||
errors.push('Invalid file type. Please upload a PDF, DOC, or DOCX file.');
|
errors.push('Invalid file type. Please upload a PDF, DOC, or DOCX file.');
|
||||||
}
|
}
|
||||||
|
if (uploadedFile.size > 10 * 1024 * 1024) {
|
||||||
if (uploadedFile.size > 10 * 1024 * 1024) { // 10MB limit
|
|
||||||
errors.push('File is too large. Maximum size is 10MB.');
|
errors.push('File is too large. Maximum size is 10MB.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({ error: errors.join(' ') }, { status: 400 });
|
||||||
error: errors.join(' ')
|
|
||||||
}, { status: 400 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct email body
|
|
||||||
let emailBody = `<h2>${config.subject}</h2><table style="border: 1px solid #b5b5b5; padding: 5px;">`;
|
let emailBody = `<h2>${config.subject}</h2><table style="border: 1px solid #b5b5b5; padding: 5px;">`;
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(data)) {
|
for (const [key, value] of Object.entries(data)) {
|
||||||
if (config.fields.includes(key) && key !== 'form_type' && key !== 'sample_details') {
|
if (config.fields.includes(key) && key !== 'form_type' && key !== 'sample_details') {
|
||||||
emailBody += `<tr>
|
emailBody += `<tr>
|
||||||
@ -151,7 +150,6 @@ export async function POST(request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add file info if uploaded
|
|
||||||
if (form_type === 'career' && files.resume) {
|
if (form_type === 'career' && files.resume) {
|
||||||
emailBody += `<tr>
|
emailBody += `<tr>
|
||||||
<td style="border: 1px solid #b5b5b5; padding: 5px;"><strong>Resume</strong></td>
|
<td style="border: 1px solid #b5b5b5; padding: 5px;"><strong>Resume</strong></td>
|
||||||
@ -159,20 +157,17 @@ export async function POST(request) {
|
|||||||
</tr>`;
|
</tr>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add sample details for sample form
|
|
||||||
if (form_type === 'sample' && data.sample_details) {
|
if (form_type === 'sample' && data.sample_details) {
|
||||||
try {
|
try {
|
||||||
const sampleDetails = JSON.parse(data.sample_details);
|
const sampleDetails = JSON.parse(data.sample_details);
|
||||||
if (sampleDetails && sampleDetails.length > 0) {
|
if (sampleDetails.length > 0) {
|
||||||
emailBody += `<tr>
|
emailBody += `<tr>
|
||||||
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 10px; background-color: #e8f5f3; text-align: center;"><strong>SAMPLE DETAILS</strong></td>
|
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 10px; background-color: #e8f5f3; text-align: center;"><strong>SAMPLE DETAILS</strong></td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
|
|
||||||
sampleDetails.forEach((sample, index) => {
|
sampleDetails.forEach((sample, index) => {
|
||||||
emailBody += `<tr>
|
emailBody += `<tr>
|
||||||
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 8px; background-color: #f0f8f5; font-weight: bold;">Sample ${index + 1}</td>
|
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 8px; background-color: #f0f8f5; font-weight: bold;">Sample ${index + 1}</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
|
|
||||||
Object.entries(sample).forEach(([key, value]) => {
|
Object.entries(sample).forEach(([key, value]) => {
|
||||||
if (value && String(value).trim() !== '') {
|
if (value && String(value).trim() !== '') {
|
||||||
emailBody += `<tr>
|
emailBody += `<tr>
|
||||||
@ -183,25 +178,16 @@ export async function POST(request) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.error('Error parsing sample details:', error);
|
|
||||||
emailBody += `<tr>
|
emailBody += `<tr>
|
||||||
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 5px; color: red;">Error: Could not parse sample details</td>
|
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 5px; color: red;">Error: Could not parse sample details</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emailBody += '</table>';
|
emailBody += '</table>';
|
||||||
|
|
||||||
// Determine reply-to email based on form type
|
let replyToEmail = form_type === 'sample' ? data.Email : data.email;
|
||||||
let replyToEmail;
|
|
||||||
if (form_type === 'sample') {
|
|
||||||
replyToEmail = data.Email;
|
|
||||||
} else {
|
|
||||||
replyToEmail = data.email;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create transporter
|
|
||||||
const transporter = nodemailer.createTransport({
|
const transporter = nodemailer.createTransport({
|
||||||
host: 'smtp.gmail.com',
|
host: 'smtp.gmail.com',
|
||||||
port: 587,
|
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 = {
|
const mailOptions = {
|
||||||
from: `${emailConfig.from_email_name} <${emailConfig.from_email}>`,
|
from: `${emailConfig.from_email_name} <${emailConfig.from_email}>`,
|
||||||
to: `${emailConfig.to_email_name} <${emailConfig.to_email}>`,
|
to: `${emailConfig.to_email_name} <${emailConfig.to_email}>`,
|
||||||
replyTo: replyToEmail || emailConfig.from_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,
|
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) {
|
if (form_type === 'career' && files.resume) {
|
||||||
const fileBuffer = await files.resume.arrayBuffer();
|
const fileBuffer = await files.resume.arrayBuffer();
|
||||||
mailOptions.attachments = [{
|
mailOptions.attachments = [{
|
||||||
@ -231,18 +224,24 @@ export async function POST(request) {
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send email
|
|
||||||
await transporter.sendMail(mailOptions);
|
await transporter.sendMail(mailOptions);
|
||||||
|
|
||||||
return NextResponse.json({
|
// PI email for sample form
|
||||||
success: true,
|
if (form_type === 'sample') {
|
||||||
message: config.successMessage
|
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) {
|
} catch (error) {
|
||||||
console.error('Email sending error:', error);
|
console.error('Email sending error:', error);
|
||||||
return NextResponse.json({
|
return NextResponse.json({ error: 'Error sending email. Please try again later.' }, { status: 500 });
|
||||||
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."
|
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",
|
title: "Bioinformatics Analysis",
|
||||||
description: "NGS produces vast amounts of data, supporting complex research through advanced bioinformatic analysis."
|
description: "NGS produces vast amounts of data, supporting complex research through advanced bioinformatic analysis."
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ const CareerPage = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="page-content contact-us">
|
<div className="page-content contact-us">
|
||||||
<CareerHero />
|
<CareerHero />
|
||||||
<div className="h-6"></div>
|
{/* <div className="h-2"></div> */}
|
||||||
<CareerSection />
|
<CareerSection />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import CareerInfo from './CareerInfo';
|
|||||||
|
|
||||||
const CareerSection = () => {
|
const CareerSection = () => {
|
||||||
return (
|
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="container mx-auto max-w-none px-4">
|
||||||
<div className="flex flex-col lg:flex-row gap-6">
|
<div className="flex flex-col lg:flex-row gap-6">
|
||||||
<CareerInfo />
|
<CareerInfo />
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const ContactPage = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="page-content contact-us">
|
<div className="page-content contact-us">
|
||||||
<PageTitle />
|
<PageTitle />
|
||||||
<div className="h-6"></div>
|
{/* <div className="h-6"></div> */}
|
||||||
<ContactSection />
|
<ContactSection />
|
||||||
<ContactMap />
|
<ContactMap />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -39,7 +39,7 @@ const Footer = () => {
|
|||||||
</address>
|
</address>
|
||||||
|
|
||||||
{/* Social Links */}
|
{/* Social Links */}
|
||||||
<div className="flex space-x-4 mt-8">
|
<div className="flex mt-8">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@ -136,7 +136,7 @@ const Footer = () => {
|
|||||||
<div className="container mx-auto px-4 py-4">
|
<div className="container mx-auto px-4 py-4">
|
||||||
<div className="flex flex-col md:flex-row justify-between items-center text-sm">
|
<div className="flex flex-col md:flex-row justify-between items-center text-sm">
|
||||||
<p>
|
<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>
|
</p>
|
||||||
<ul className="flex space-x-6 mt-3 md:mt-0">
|
<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>
|
<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">
|
<table className="w-full border-collapse border border-gray-300 text-sm">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col style={{width: '25%'}} />
|
<col style={{width: '25%'}} />
|
||||||
<col style={{width: '25%'}} />
|
<col style={{width: '40%'}} />
|
||||||
<col style={{width: '50%'}} />
|
<col style={{width: '35%'}} />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="bg-teal-50">
|
<tr className="bg-teal-50">
|
||||||
|
|||||||
@ -8,70 +8,29 @@ import SampleDetailsSection from './SampleDetailsSection';
|
|||||||
|
|
||||||
const SampleFormContainer = () => {
|
const SampleFormContainer = () => {
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
// Customer Information
|
Principal_Investigator: '', Email: '', Company_Institution: '', Contact_Number: '',
|
||||||
Principal_Investigator: '',
|
Address: '', City: '', State: '', Pin: '', Secondary_Contact: '', Secondary_Email: '',
|
||||||
Email: '',
|
Secondary_Company_Institution: '', Secondary_Contact_Number: '', Project_Title: '',
|
||||||
Company_Institution: '',
|
Number_of_Samples: '', Sample_Type: '', Sample_Type_Other: '', Sample_Source: '',
|
||||||
Contact_Number: '',
|
Sample_Source_Other: '', Pathogenicity: '', Sample_Remarks: '', Service_Requested: '',
|
||||||
Address: '',
|
Service_Requested_Other: '', Type_of_Library: '', Type_of_Library_Other: '',
|
||||||
City: '',
|
Required_Library_Size: '', Required_Library_Size_Other: '', Index_Information: '',
|
||||||
State: '',
|
Kit_Information: '', Sequencing_Platform: '', Sequencing_Platform_Other: '',
|
||||||
Pin: '',
|
Sequencing_Read_Length: '', Sequencing_Read_Length_Other: '', Total_Data_Requirement: '',
|
||||||
Secondary_Contact: '',
|
Service_Remarks: '', Analysis_Requested: '', Analysis_Details: '',
|
||||||
Secondary_Email: '',
|
Reference_Genome_Available: '', Genome_Size: '', Special_Consideration: ''
|
||||||
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: '',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const [sampleDetails, setSampleDetails] = useState([
|
const [sampleDetails, setSampleDetails] = useState([{
|
||||||
{
|
Serial_Number: '', Sample_Name: '', Storage_Temp: '',
|
||||||
Serial_Number: '',
|
Preservative_Reagent: '', Temp_Information: '', Comments: ''
|
||||||
Sample_Name: '',
|
}]);
|
||||||
Storage_Temp: '',
|
|
||||||
Preservative_Reagent: '',
|
|
||||||
Temp_Information: '',
|
|
||||||
Comments: ''
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [message, setMessage] = useState('');
|
const [message, setMessage] = useState('');
|
||||||
|
const [showSuccessModal, setShowSuccessModal] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check for Excel data in sessionStorage
|
|
||||||
const excelData = sessionStorage.getItem('excelData');
|
const excelData = sessionStorage.getItem('excelData');
|
||||||
const uploadedFileName = sessionStorage.getItem('uploadedFileName');
|
const uploadedFileName = sessionStorage.getItem('uploadedFileName');
|
||||||
|
|
||||||
@ -79,11 +38,8 @@ const SampleFormContainer = () => {
|
|||||||
try {
|
try {
|
||||||
const jsonData = JSON.parse(excelData);
|
const jsonData = JSON.parse(excelData);
|
||||||
autoFillForm(jsonData);
|
autoFillForm(jsonData);
|
||||||
|
|
||||||
// Clear stored data
|
|
||||||
sessionStorage.removeItem('excelData');
|
sessionStorage.removeItem('excelData');
|
||||||
sessionStorage.removeItem('uploadedFileName');
|
sessionStorage.removeItem('uploadedFileName');
|
||||||
|
|
||||||
setMessage(`Form auto-filled from uploaded file: ${uploadedFileName}`);
|
setMessage(`Form auto-filled from uploaded file: ${uploadedFileName}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing Excel data:', error);
|
console.error('Error parsing Excel data:', error);
|
||||||
@ -93,14 +49,10 @@ const SampleFormContainer = () => {
|
|||||||
|
|
||||||
const autoFillForm = (jsonData) => {
|
const autoFillForm = (jsonData) => {
|
||||||
if (jsonData.length === 0) return;
|
if (jsonData.length === 0) return;
|
||||||
|
|
||||||
const data = jsonData[0];
|
const data = jsonData[0];
|
||||||
const newFormData = { ...formData };
|
const newFormData = { ...formData };
|
||||||
|
|
||||||
// Helper function to safely get value
|
|
||||||
const getValue = (key) => data[key] ? data[key].toString().trim() : '';
|
const getValue = (key) => data[key] ? data[key].toString().trim() : '';
|
||||||
|
|
||||||
// Customer Information
|
|
||||||
newFormData.Principal_Investigator = getValue('Principal Investigator');
|
newFormData.Principal_Investigator = getValue('Principal Investigator');
|
||||||
newFormData.Email = getValue('Email');
|
newFormData.Email = getValue('Email');
|
||||||
newFormData.Company_Institution = getValue('Company/Institution');
|
newFormData.Company_Institution = getValue('Company/Institution');
|
||||||
@ -114,7 +66,6 @@ const SampleFormContainer = () => {
|
|||||||
newFormData.Secondary_Company_Institution = getValue('Secondary Company/Institution');
|
newFormData.Secondary_Company_Institution = getValue('Secondary Company/Institution');
|
||||||
newFormData.Secondary_Contact_Number = getValue('Secondary Contact Number');
|
newFormData.Secondary_Contact_Number = getValue('Secondary Contact Number');
|
||||||
|
|
||||||
// Sample Information
|
|
||||||
newFormData.Project_Title = getValue('Project Title');
|
newFormData.Project_Title = getValue('Project Title');
|
||||||
newFormData.Number_of_Samples = getValue('Number of Samples');
|
newFormData.Number_of_Samples = getValue('Number of Samples');
|
||||||
newFormData.Sample_Type = getValue('Sample Type');
|
newFormData.Sample_Type = getValue('Sample Type');
|
||||||
@ -124,7 +75,6 @@ const SampleFormContainer = () => {
|
|||||||
newFormData.Pathogenicity = getValue('Pathogenicity');
|
newFormData.Pathogenicity = getValue('Pathogenicity');
|
||||||
newFormData.Sample_Remarks = getValue('Sample Remarks');
|
newFormData.Sample_Remarks = getValue('Sample Remarks');
|
||||||
|
|
||||||
// Service Information
|
|
||||||
newFormData.Service_Requested = getValue('Service Requested');
|
newFormData.Service_Requested = getValue('Service Requested');
|
||||||
newFormData.Service_Requested_Other = getValue('Service Requested Other');
|
newFormData.Service_Requested_Other = getValue('Service Requested Other');
|
||||||
newFormData.Type_of_Library = getValue('Type of Library');
|
newFormData.Type_of_Library = getValue('Type of Library');
|
||||||
@ -140,7 +90,6 @@ const SampleFormContainer = () => {
|
|||||||
newFormData.Total_Data_Requirement = getValue('Total Data Requirement');
|
newFormData.Total_Data_Requirement = getValue('Total Data Requirement');
|
||||||
newFormData.Service_Remarks = getValue('Service Remarks');
|
newFormData.Service_Remarks = getValue('Service Remarks');
|
||||||
|
|
||||||
// Bioinformatics Information
|
|
||||||
newFormData.Analysis_Requested = getValue('Analysis Requested');
|
newFormData.Analysis_Requested = getValue('Analysis Requested');
|
||||||
newFormData.Analysis_Details = getValue('Analysis Details');
|
newFormData.Analysis_Details = getValue('Analysis Details');
|
||||||
newFormData.Reference_Genome_Available = getValue('Reference Genome Available');
|
newFormData.Reference_Genome_Available = getValue('Reference Genome Available');
|
||||||
@ -149,21 +98,20 @@ const SampleFormContainer = () => {
|
|||||||
|
|
||||||
setFormData(newFormData);
|
setFormData(newFormData);
|
||||||
|
|
||||||
// Handle Sample Details
|
const sampleDetailsData = jsonData.filter(row =>
|
||||||
const sampleDetailsData = jsonData.filter(row =>
|
row['Serial Number'] || row['Sample Name'] ||
|
||||||
row['Serial Number'] || row['Sample Name'] ||
|
row['Storage Temp'] || row['Preservative Reagent'] ||
|
||||||
row['Storage Temp'] || row['Preservative Reagent'] ||
|
|
||||||
row['Temp Information'] || row['Comments']
|
row['Temp Information'] || row['Comments']
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sampleDetailsData.length > 0) {
|
if (sampleDetailsData.length > 0) {
|
||||||
const newSampleDetails = sampleDetailsData.map(sample => ({
|
const newSampleDetails = sampleDetailsData.map(sample => ({
|
||||||
Serial_Number: getValue('Serial Number'),
|
Serial_Number: sample['Serial Number'] || '',
|
||||||
Sample_Name: getValue('Sample Name'),
|
Sample_Name: sample['Sample Name'] || '',
|
||||||
Storage_Temp: getValue('Storage Temp'),
|
Storage_Temp: sample['Storage Temp'] || '',
|
||||||
Preservative_Reagent: getValue('Preservative Reagent'),
|
Preservative_Reagent: sample['Preservative Reagent'] || '',
|
||||||
Temp_Information: getValue('Temp Information'),
|
Temp_Information: sample['Temp Information'] || '',
|
||||||
Comments: getValue('Comments')
|
Comments: sample['Comments'] || ''
|
||||||
}));
|
}));
|
||||||
setSampleDetails(newSampleDetails);
|
setSampleDetails(newSampleDetails);
|
||||||
}
|
}
|
||||||
@ -179,37 +127,28 @@ const SampleFormContainer = () => {
|
|||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
setMessage(''); // Clear previous messages
|
setMessage('');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const formDataToSend = new FormData();
|
const formDataToSend = new FormData();
|
||||||
|
|
||||||
// Add form data
|
|
||||||
Object.keys(formData).forEach(key => {
|
Object.keys(formData).forEach(key => {
|
||||||
if (formData[key]) {
|
if (formData[key]) {
|
||||||
formDataToSend.append(key, formData[key]);
|
formDataToSend.append(key, formData[key]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add sample details as JSON string
|
|
||||||
formDataToSend.append('sample_details', JSON.stringify(sampleDetails));
|
formDataToSend.append('sample_details', JSON.stringify(sampleDetails));
|
||||||
formDataToSend.append('form_type', 'sample');
|
formDataToSend.append('form_type', 'sample');
|
||||||
|
|
||||||
console.log('Submitting form data:', formData);
|
|
||||||
console.log('Sample details:', sampleDetails);
|
|
||||||
|
|
||||||
const response = await fetch('/api/forms', {
|
const response = await fetch('/api/forms', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formDataToSend,
|
body: formDataToSend,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
console.log('API Response:', result);
|
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
setMessage(result.message);
|
setMessage(result.message);
|
||||||
|
setShowSuccessModal(true); // show modal instead of green alert
|
||||||
// Reset form after successful submission
|
|
||||||
setFormData({
|
setFormData({
|
||||||
Principal_Investigator: '', Email: '', Company_Institution: '', Contact_Number: '',
|
Principal_Investigator: '', Email: '', Company_Institution: '', Contact_Number: '',
|
||||||
Address: '', City: '', State: '', Pin: '', Secondary_Contact: '', Secondary_Email: '',
|
Address: '', City: '', State: '', Pin: '', Secondary_Contact: '', Secondary_Email: '',
|
||||||
@ -223,7 +162,6 @@ const SampleFormContainer = () => {
|
|||||||
Service_Remarks: '', Analysis_Requested: '', Analysis_Details: '',
|
Service_Remarks: '', Analysis_Requested: '', Analysis_Details: '',
|
||||||
Reference_Genome_Available: '', Genome_Size: '', Special_Consideration: ''
|
Reference_Genome_Available: '', Genome_Size: '', Special_Consideration: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
setSampleDetails([{
|
setSampleDetails([{
|
||||||
Serial_Number: '', Sample_Name: '', Storage_Temp: '',
|
Serial_Number: '', Sample_Name: '', Storage_Temp: '',
|
||||||
Preservative_Reagent: '', Temp_Information: '', Comments: ''
|
Preservative_Reagent: '', Temp_Information: '', Comments: ''
|
||||||
@ -231,7 +169,6 @@ const SampleFormContainer = () => {
|
|||||||
} else {
|
} else {
|
||||||
setMessage('Error: ' + (result.error || 'Form submission failed'));
|
setMessage('Error: ' + (result.error || 'Form submission failed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error submitting form:', error);
|
console.error('Error submitting form:', error);
|
||||||
setMessage('Error: Network error. Please check your connection and try again.');
|
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="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">
|
<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">
|
<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="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}
|
{message}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<CustomerInfoSection
|
<CustomerInfoSection formData={formData} onInputChange={handleInputChange} />
|
||||||
formData={formData}
|
<SampleInfoSection formData={formData} onInputChange={handleInputChange} />
|
||||||
onInputChange={handleInputChange}
|
<ServiceInfoSection formData={formData} onInputChange={handleInputChange} />
|
||||||
/>
|
<BioinformaticsSection formData={formData} onInputChange={handleInputChange} />
|
||||||
|
<SampleDetailsSection sampleDetails={sampleDetails} setSampleDetails={setSampleDetails} />
|
||||||
<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">
|
<div className="text-center py-6">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
@ -290,8 +208,50 @@ const SampleFormContainer = () => {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SampleFormContainer;
|
export default SampleFormContainer;
|
||||||
|
|||||||
@ -1,96 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const EnrichmentPipeline = ({
|
const EnrichmentPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/resequencing.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-5xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block sm:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
// Fallback message
|
||||||
<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">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
<p>Please provide SVG content or URL</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,126 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const EpigenomicsPipeline = ({
|
const EpigenomicsPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/epigenomics.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...middleSteps, ...rightSteps];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-7xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block lg:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrows */}
|
// Fallback message
|
||||||
{/* Arrow from Aligned to Reference Genome to Peak Calling */}
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<div className="absolute bottom-4 left-1/3 transform -translate-x-1/2">
|
<p>Please provide SVG content or URL</p>
|
||||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,96 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const GenomeMappingPipeline = ({
|
const GenomeMappingPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/genoemapping.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-5xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block sm:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
// Fallback message
|
||||||
<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">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
<p>Please provide SVG content or URL</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,124 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const MetagenomicsPipeline = ({
|
const MetagenomicsPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftColumn = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/metagenomics.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine all steps for mobile layout
|
|
||||||
const mobileSteps = [
|
|
||||||
...leftColumn,
|
|
||||||
...middleColumn.slice().reverse(),
|
|
||||||
...rightColumn
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-600 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-6xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block lg:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrows */}
|
// Fallback message
|
||||||
{/* Arrow from left to middle column */}
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<div className="absolute bottom-8 left-1/3 transform -translate-x-1/2 flex items-center justify-center">
|
<p>Please provide SVG content or URL</p>
|
||||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,96 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const SingleCellPipeline = ({
|
const SingleCellPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/singlecell.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-5xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block sm:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
// Fallback message
|
||||||
<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">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
<p>Please provide SVG content or URL</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,96 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const WGSDeNovoPipeline = ({
|
const WGSDeNovoPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/denovo.svg",
|
||||||
"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)"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-5xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block sm:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
// Fallback message
|
||||||
<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">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
<p>Please provide SVG content or URL</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,96 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const WGSResequencingPipeline = ({
|
const WGSResequencingPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/resequencing.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-5xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block sm:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrow positioned between Primary and Secondary Assembly */}
|
// Fallback message
|
||||||
<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">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<ArrowRight className={`w-6 h-6 sm:w-8 sm:h-8 ${arrowColor}`} />
|
<p>Please provide SVG content or URL</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,130 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const CircularRNAPipeline = ({
|
const CircularRNAPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/circularrna.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-5xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block sm:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Custom arrows from "Alignment to Reference Genome" */}
|
// Fallback message
|
||||||
<div className="absolute bottom-12 sm:bottom-16 lg:bottom-[2rem] left-1/2 transform -translate-x-1/2">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<div className="relative w-0 h-0">
|
<p>Please provide SVG content or URL</p>
|
||||||
|
|
||||||
{/* 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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,123 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const DegradomeSequencingPipeline = ({
|
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",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-blue-200",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-gray-800",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
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 (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-6xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block lg:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{[...leftSteps, ...rightSteps.slice().reverse(), ...middleSteps].map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < leftSteps.length + rightSteps.length + middleSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrow from left to right (after alignment) */}
|
// Fallback message
|
||||||
<div className="absolute bottom-4 left-1/3 transform -translate-x-1/2 flex items-center justify-center">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
<p>Please provide SVG content or URL</p>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,127 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const IsoformPipeline = ({
|
const IsoformPipeline = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/isoseqrna.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-5xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block sm:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Diagonal Arrow from High Quality Sequencing Data to Alignment to Reference Genome */}
|
// Fallback message
|
||||||
<div className="absolute top-80 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<svg
|
<p>Please provide SVG content or URL</p>
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</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 (
|
return (
|
||||||
<section className="py-8 lg:py-12 bg-gray-50">
|
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
||||||
<div className="container mx-auto max-w-none px-4 lg:px-6">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className="text-2xl lg:text-3xl text-gray-700 text-left pb-2 mb-6 lg:mb-6">
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
Bioinformatics Pipeline
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Image */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<img
|
<div className="w-full max-w-6xl">
|
||||||
src="/images/lncrna-bioinformatics-pipeline.jpg"
|
{/* SVG Container with responsive sizing */}
|
||||||
alt="lncRNA Sequencing Bioinformatics Pipeline Workflow"
|
<div className={`w-full ${svgClassName}`}>
|
||||||
className="max-w-full h-auto rounded-lg"
|
{svgUrl ? (
|
||||||
/>
|
// If SVG URL/path is provided
|
||||||
</div>
|
<img
|
||||||
|
src={svgUrl}
|
||||||
{/* Pipeline Description */}
|
alt="Flowchart diagram"
|
||||||
<div className="mt-6 text-center">
|
className="w-full h-auto object-contain"
|
||||||
<p className="text-gray-600 text-sm lg:text-base">
|
/>
|
||||||
lncRNA sequencing bioinformatics pipeline for long non-coding RNA analysis and expression profiling
|
) : svgContent ? (
|
||||||
</p>
|
// 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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -30,4 +53,4 @@ const LncRNABioinformatics = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LncRNABioinformatics
|
export default LncRNABioinformatics;
|
||||||
@ -1,188 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const MetatranscriptomicsPipeline = ({
|
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",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-blue-200",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-blue-800",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
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 (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-6xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block lg:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{topSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < topSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
|
|
||||||
{/* 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>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : (
|
||||||
|
// Fallback message
|
||||||
{/* Desktop Layout */}
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<div className="hidden lg:block">
|
<p>Please provide SVG content or URL</p>
|
||||||
{/* 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>
|
|
||||||
))}
|
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,98 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ArrowDown, ArrowRight, ArrowUp } from 'lucide-react';
|
|
||||||
|
|
||||||
const SRNABioinformatics = ({
|
const SRNABioinformatics = ({
|
||||||
title = "Bioinformatics Pipeline",
|
title = "Bioinformatics Pipeline",
|
||||||
leftSteps = [
|
svgContent = null, // Pass your SVG content here as JSX
|
||||||
"Raw Sequencing Data (fastq files)",
|
svgUrl = "/images/flowchart/smallrna.svg",
|
||||||
"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"
|
|
||||||
],
|
|
||||||
backgroundColor = "bg-gray-50",
|
backgroundColor = "bg-gray-50",
|
||||||
cardColor = "bg-gray-300",
|
textColor = "text-gray-700",
|
||||||
textColor = "text-teal-600",
|
|
||||||
arrowColor = "text-gray-600",
|
|
||||||
className = "",
|
className = "",
|
||||||
cardClassName = "",
|
titleClassName = "",
|
||||||
titleClassName = ""
|
svgClassName = "",
|
||||||
|
containerClassName = ""
|
||||||
}) => {
|
}) => {
|
||||||
// Combine steps for mobile layout
|
|
||||||
const mobileSteps = [...leftSteps, ...rightSteps.slice().reverse()];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`py-6 sm:py-8 lg:py-12 ${backgroundColor} ${className}`}>
|
<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">
|
<div className={`container mx-auto max-w-none px-3 sm:px-4 lg:px-6 ${containerClassName}`}>
|
||||||
<h2 className={`text-gray-700 text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
<h2 className={`${textColor} text-left pb-4 sm:pb-6 text-xl sm:text-2xl lg:text-3xl font-normal ${titleClassName}`}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Pipeline Flowchart */}
|
{/* SVG Flowchart Container */}
|
||||||
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
<div className="bg-white rounded-xl shadow-lg p-4 sm:p-6 lg:p-8">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="w-full max-w-5xl">
|
<div className="w-full max-w-6xl">
|
||||||
<div className="relative">
|
{/* SVG Container with responsive sizing */}
|
||||||
{/* Mobile Layout - Single Column */}
|
<div className={`w-full ${svgClassName}`}>
|
||||||
<div className="block sm:hidden">
|
{svgUrl ? (
|
||||||
<div className="flex flex-col items-center space-y-3">
|
// If SVG URL/path is provided
|
||||||
{mobileSteps.map((step, index) => (
|
<img
|
||||||
<React.Fragment key={index}>
|
src={svgUrl}
|
||||||
<div className={`${cardColor} rounded-lg p-3 w-full text-center border ${cardClassName}`}>
|
alt="Flowchart diagram"
|
||||||
<h3 className={`text-xs font-medium ${textColor}`}>{step}</h3>
|
className="w-full h-auto object-contain"
|
||||||
</div>
|
/>
|
||||||
{index < mobileSteps.length - 1 && (
|
) : svgContent ? (
|
||||||
<ArrowDown className={`w-5 h-5 ${arrowColor}`} />
|
// If SVG content is provided as JSX
|
||||||
)}
|
<div className="w-full">
|
||||||
</React.Fragment>
|
<div className="w-full">
|
||||||
))}
|
{svgContent}
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
{/* Horizontal Arrow from Transcript Assembly to Transcript Assembly Validation */}
|
// Fallback message
|
||||||
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex items-center justify-center">
|
<div className="flex items-center justify-center h-40 text-gray-500">
|
||||||
<ArrowRight className={`w-8 h-8 ${arrowColor}`} />
|
<p>Please provide SVG content or URL</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</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 TitleBar from '../../components/shared/TitleBar';
|
||||||
import WTSIntroduction from './components/WTSIntroduction';
|
import WTSIntroduction from './components/WTSIntroduction';
|
||||||
import WTSAdvantages from './components/WTSAdvantages';
|
import WTSAdvantages from './components/WTSAdvantages';
|
||||||
|
import WTSPipeline from './components/WTSPipeline';
|
||||||
import WTSApplications from './components/WTSApplications';
|
import WTSApplications from './components/WTSApplications';
|
||||||
import WTSSpecifications from './components/WTSSpecifications';
|
import WTSSpecifications from './components/WTSSpecifications';
|
||||||
import PageLayout from '../../components/Layout/PageLayout';
|
import PageLayout from '../../components/Layout/PageLayout';
|
||||||
@ -21,6 +22,7 @@ export default function WholeTranscriptomeSequencingPage() {
|
|||||||
/>
|
/>
|
||||||
<WTSIntroduction />
|
<WTSIntroduction />
|
||||||
<WTSAdvantages />
|
<WTSAdvantages />
|
||||||
|
<WTSPipeline/>
|
||||||
<WTSApplications />
|
<WTSApplications />
|
||||||
<WTSSpecifications />
|
<WTSSpecifications />
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
|
|||||||
10
package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"name": "nextjs",
|
"name": "nextjs",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@heroicons/react": "^2.2.0",
|
||||||
"lucide-react": "^0.525.0",
|
"lucide-react": "^0.525.0",
|
||||||
"next": "^15.2.0",
|
"next": "^15.2.0",
|
||||||
"nodemailer": "^7.0.3",
|
"nodemailer": "^7.0.3",
|
||||||
@ -214,6 +215,15 @@
|
|||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"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": {
|
"node_modules/@humanfs/core": {
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@heroicons/react": "^2.2.0",
|
||||||
"lucide-react": "^0.525.0",
|
"lucide-react": "^0.525.0",
|
||||||
"next": "^15.2.0",
|
"next": "^15.2.0",
|
||||||
"nodemailer": "^7.0.3",
|
"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 |