Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49bcd4be0d | ||
|
|
0534e5dfc0 | ||
|
|
5f0c15399d | ||
|
|
461917a15e | ||
|
|
253c1c9ba5 | ||
|
|
468b7f3d68 | ||
|
|
1ca741eeae |
73
docs/TECH_STACK.md
Normal file
73
docs/TECH_STACK.md
Normal file
@ -0,0 +1,73 @@
|
||||
# Technology Stack & Architecture
|
||||
|
||||
이 프로젝트는 **Headless CMS** 아키텍처를 기반으로 하며, 프론트엔드와 백엔드가 분리되어 운영됩니다. 다음은 프로젝트에 사용된 주요 기술과 도구에 대한 명세입니다.
|
||||
|
||||
## 1. Frontend (사용자 인터페이스)
|
||||
|
||||
사용자에게 보여지는 웹사이트 화면은 **React**를 사용하여 구축되었습니다.
|
||||
|
||||
### **Core Framework & Language**
|
||||
* **React 19**: 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리입니다.
|
||||
* *이용 방식*: 컴포넌트(Component) 단위로 UI를 쪼개어 개발(예: `Navbar`, `Footer`, `PostCard`)함으로써 재사용성과 유지보수성을 높였습니다.
|
||||
* **JavaScript (ES6+)**: 최신 자바스크립트 문법을 사용합니다.
|
||||
* *주요 기능*: `Async/Await` (비동기 처리), `Arrow Functions`, `Destructuring` 등을 적극 활용했습니다.
|
||||
* **Vite**: 차세대 프론트엔드 빌드 도구입니다.
|
||||
* *역할*: 개발 서버를 빠르게 구동하고, 배포를 위해 코드를 최적화하여 빌드(Build)하는 역할을 합니다. (기존 Create-React-App보다 훨씬 빠름)
|
||||
|
||||
### **Routing & Navigation**
|
||||
* **React Router DOM**: SPA(Single Page Application) 구현을 위한 라우팅 라이브러리입니다.
|
||||
* *역할*: 페이지를 새로고침하지 않고도 URL(`url/about`, `url/news` 등)에 따라 다른 화면을 보여줍니다.
|
||||
|
||||
### **Styling (디자인)**
|
||||
* **Vanilla CSS**: 별도의 CSS 프레임워크(Tailwind, Bootstrap 등) 없이 순수 CSS를 사용했습니다.
|
||||
* *파일*: `src/styles/main.css` 하나로 통합 관리됩니다.
|
||||
* *특징*: CSS Variables(`var(--primary-color)`)를 사용하여 색상 테마를 일관되게 관리하며, 반응형 디자인(`@media`)이 적용되어 있습니다.
|
||||
|
||||
### **Data Communication (통신)**
|
||||
* **Axios**: 서버와 통신하기 위한 HTTP 클라이언트입니다.
|
||||
* *역할*: 워드프레스 API(`wp-json`)에 요청을 보내 뉴스 글이나 데이터를 가져옵니다.
|
||||
|
||||
### **Security & Utilities**
|
||||
* **DOMPurify**: 워드프레스에서 가져온 HTML 본문을 안전하게 렌더링하기 위해 XSS 공격(악성 스크립트)을 방지하는 라이브러리입니다.
|
||||
* **Context Menu Blocking**: 마우스 우클릭 및 드래그를 방지하여 콘텐츠 무단 복사를 막는 로직이 포함되어 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 2. Backend (CMS & Data)
|
||||
|
||||
데이터 관리와 콘텐츠 작성은 **WordPress**를 사용합니다.
|
||||
|
||||
* **WordPress (Headless Mode)**: 전통적인 워드프레스 테마를 사용하지 않고, 오직 **데이터 저장소** 및 **관리자 페이지** 역할만 수행합니다.
|
||||
* **REST API**: 워드프레스에 내장된 API를 통해 프론트엔드(React)로 JSON 데이터를 전달합니다.
|
||||
* **PHP 8.3**: 워드프레스 구동을 위한 서버 사이드 언어입니다.
|
||||
* **MariaDB 10**: 게시글, 댓글 등 모든 데이터가 저장되는 데이터베이스입니다.
|
||||
|
||||
---
|
||||
|
||||
## 3. Infrastructure (인프라)
|
||||
|
||||
* **Synology Web Station**: 웹 서버 호스팅 환경입니다.
|
||||
* **Apache HTTP Server 2.4**: React 빌드 파일(정적 파일)과 워드프레스(PHP)를 서비스하는 웹 서버 소프트웨어입니다.
|
||||
* **Gitea**: 소스 코드의 버전 관리를 담당하는 자체 호스팅 Git 서버입니다.
|
||||
|
||||
---
|
||||
|
||||
## 4. Contact Form Security (문의하기 보안 정책)
|
||||
|
||||
문의하기 기능(`Contact.jsx`)에는 스팸 봇(Bot) 및 어뷰징 방지를 위해 **4단계 보안 시스템**이 적용되어 있습니다.
|
||||
|
||||
### **1. Honeypot Field (허니팟)**
|
||||
* **원리**: 사용자(사람)의 눈에는 보이지 않는 숨겨진 입력 필드(`honeypot`)를 폼에 배치합니다.
|
||||
* **방어**: 자동화된 봇은 모든 필드를 채우려는 특성이 있습니다. 이 숨겨진 필드에 값이 입력되면 즉시 **스팸으로 간주하여 전송을 차단**합니다.
|
||||
|
||||
### **2. Rate Limiting (전송 빈도 제한)**
|
||||
* **원리**: 브라우저의 `localStorage`를 활용하여 마지막으로 문의를 전송한 시각을 기록합니다.
|
||||
* **방어**: 동일한 브라우저에서 **1분(60초) 이내**에 연속으로 문의를 보낼 수 없도록 차단하여, 메일 폭탄(Email Bombing) 공격을 예방합니다.
|
||||
|
||||
### **3. Input Validation (입력값 검증)**
|
||||
* **원리**: 사용자가 입력한 데이터가 유효한 형식인지 클라이언트 단에서 1차 검증합니다.
|
||||
* **방어**: 특히 연락처 필드는 한국 휴대폰 번호 정규식(`^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})$`)을 통과해야만 전송 버튼이 작동하여, 무의미한 데이터 전송을 막습니다.
|
||||
|
||||
### **4. Secure Token Submission**
|
||||
* **원리**: 이메일 주소를 HTML 소스코드에 직접 노출(`mailto:` 등)하지 않습니다.
|
||||
* **방어**: `FormSubmit` 서비스의 **암호화된 고유 토큰**을 사용하여 데이터를 전송하므로, 크롤러에 의한 이메일 주소 수집을 원천적으로 차단합니다.
|
||||
@ -7,7 +7,7 @@ React 앱(`sokuree.com`)이 데이터를 가져오기 위해 필요한 백엔드
|
||||
다음 패키지들이 설치되어 있어야 합니다.
|
||||
- **Web Station**
|
||||
- **Apache HTTP Server 2.4** (또는 Nginx)
|
||||
- **PHP 8.0 이상** (Headless 모드는 최신 PHP 권장)
|
||||
- **PHP 8.3 이상** (Headless 모드는 최신 PHP 권장)
|
||||
- **MariaDB 10** (데이터베이스)
|
||||
- **phpMyAdmin** (DB 관리용, 선택사항이나 강력 추천)
|
||||
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" href="/src/assets/logo.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>SmartBiz Tech - 소상공인 스마트 기술 파트너</title>
|
||||
<title>SOKUREE</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@ -24,6 +24,8 @@ function ScrollToTopComp() {
|
||||
return null;
|
||||
}
|
||||
|
||||
import Platform from './pages/Platform';
|
||||
|
||||
function App() {
|
||||
// Global Content Protection
|
||||
useEffect(() => {
|
||||
@ -43,6 +45,7 @@ function App() {
|
||||
<Route path="/" element={<Layout />}>
|
||||
<Route index element={<Navigate to="/about" replace />} />
|
||||
<Route path="about" element={<About />} />
|
||||
<Route path="platform" element={<Platform />} />
|
||||
<Route path="services" element={<ServiceDetail />} />
|
||||
<Route path="services/:serviceId" element={<ServiceDetail />} />
|
||||
<Route path="cases" element={<Cases />} />
|
||||
|
||||
BIN
src/assets/214742.png
Normal file
BIN
src/assets/214742.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 216 KiB |
BIN
src/assets/logo.ico
Normal file
BIN
src/assets/logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 230 KiB |
@ -1,23 +1,26 @@
|
||||
const About = () => {
|
||||
return (
|
||||
<section id="about" className="section-padding bg-light">
|
||||
<div className="container">
|
||||
<h2 className="section-title">회사 소개</h2>
|
||||
<div className="about-content">
|
||||
<div className="about-text">
|
||||
<h3>소상공인과 함께 성장하는 스마트 파트너</h3>
|
||||
<p>
|
||||
SmartBiz Tech는 급변하는 디지털 시대에 소상공인 여러분이 경쟁력을 갖출 수 있도록
|
||||
최고의 스마트 기술을 합리적인 가격에 공급합니다.
|
||||
</p>
|
||||
<p>
|
||||
단순한 기기 판매가 아닌, 매장 환경 분석부터 설치, 유지보수까지
|
||||
원스톱 서비스를 제공하여 사장님은 경영에만 집중하실 수 있도록 돕겠습니다.
|
||||
</p>
|
||||
</div>
|
||||
<>
|
||||
<section className="about-hero">
|
||||
<div className="about-intro">
|
||||
<p>
|
||||
Sokuree Consultant는 현장의 목소리(데이터)에서 필요한 정보를 <br className="hidden md:block" />
|
||||
시스템(System)화 하여 기업의 지속 가능한 성장을 지원합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section className="vision-mission-grid">
|
||||
<div className="vision-card">
|
||||
<h3>Vision</h3>
|
||||
<p>누구나 쉽게 스마트 경영을 실현하는 세상</p>
|
||||
</div>
|
||||
<div className="vision-card">
|
||||
<h3>Mission</h3>
|
||||
<p>복잡한 기술을 현장에 맞게 단순화하고, 실질적인 성과를 창출하는 것</p>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
43
src/components/CaseItem.jsx
Normal file
43
src/components/CaseItem.jsx
Normal file
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
|
||||
const CaseItem = ({ study }) => {
|
||||
return (
|
||||
<div className="case-card">
|
||||
{/* Image Section */}
|
||||
{study.image ? (
|
||||
<div className="case-image-wrapper">
|
||||
<img
|
||||
src={study.image}
|
||||
alt={study.title}
|
||||
className="case-image"
|
||||
/>
|
||||
<div className="case-category-badge">
|
||||
{study.category.split('/')[0]}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="case-bar"></div>
|
||||
)}
|
||||
|
||||
{/* Content Section */}
|
||||
<div className="case-content">
|
||||
{!study.image && (
|
||||
<div className="case-category-text">
|
||||
{study.category}
|
||||
</div>
|
||||
)}
|
||||
<h3 className="case-card-title">{study.title}</h3>
|
||||
<div>
|
||||
<span className="case-result-badge">
|
||||
성과: {study.result}
|
||||
</span>
|
||||
</div>
|
||||
<p className="case-details">
|
||||
{study.details}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CaseItem;
|
||||
30
src/components/CasesPreview.jsx
Normal file
30
src/components/CasesPreview.jsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const CasesPreview = () => {
|
||||
return (
|
||||
<section className="section-padding">
|
||||
<div className="container">
|
||||
<h2 className="section-title">성공 사례</h2>
|
||||
<div className="solutions-grid">
|
||||
<div className="solution-card">
|
||||
<h3>H사 스마트공장 구축</h3>
|
||||
<p>생산성 30% 향상, 불량률 50% 감소</p>
|
||||
</div>
|
||||
<div className="solution-card">
|
||||
<h3>D사 ISO 인증 획득</h3>
|
||||
<p>내부 심사원 양성 및 프로세스 정립</p>
|
||||
</div>
|
||||
<div className="solution-card">
|
||||
<h3>K사 그룹웨어 도입</h3>
|
||||
<p>재고 관리 자동화 및 업무 효율화</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ textAlign: 'center', marginTop: '40px' }}>
|
||||
<Link to="/cases" className="btn btn-primary">사례 더 보기</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default CasesPreview;
|
||||
@ -6,10 +6,10 @@ const Footer = () => {
|
||||
<div className="container footer-container">
|
||||
<div className="footer-info">
|
||||
<h3>Sokuree Consultant</h3>
|
||||
<p>代表: 홍길동 | Business License: 000-00-00000</p>
|
||||
<p>주소: 서울특별시 ... (추후 업데이트)</p>
|
||||
<p>대표: 최병규 | Business License: 000-00-00000</p>
|
||||
<p>주소: 전북 순창군 ... (추후 업데이트)</p>
|
||||
<p>
|
||||
이메일: <a href={`mailto:${'contact'}@${'sokuree.com'}`} style={{ color: '#ccc', textDecoration: 'none' }} onClick={(e) => { e.currentTarget.href = `mailto:contact@sokuree.com`; }}>{'contact'}@{'sokuree.com'}</a> | 전화: 02-0000-0000
|
||||
이메일: <a href={`mailto:${'contact'}@${'sokuree.com'}`} style={{ color: '#ccc', textDecoration: 'none' }} onClick={(e) => { e.currentTarget.href = `mailto:contact@sokuree.com`; }}>{'contact'}@{'sokuree.com'}</a> | 전화: 010-2125-0217
|
||||
</p>
|
||||
</div>
|
||||
<div className="footer-links">
|
||||
|
||||
31
src/components/LatestNews.jsx
Normal file
31
src/components/LatestNews.jsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { usePosts } from '../hooks/usePosts';
|
||||
import PostCard from './PostCard';
|
||||
|
||||
const LatestNews = () => {
|
||||
const { posts, loading, error } = usePosts(1, 3); // Fetch 3 latest posts
|
||||
|
||||
if (loading) return null;
|
||||
if (error) return null;
|
||||
if (posts.length === 0) return null;
|
||||
|
||||
return (
|
||||
<section className="section-padding bg-light">
|
||||
<div className="container">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<h2 className="section-title mb-0">최신 소식</h2>
|
||||
<Link to="/news" className="text-primary font-semibold hover:underline">
|
||||
전체 보기 →
|
||||
</Link>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{posts.map((post) => (
|
||||
<PostCard key={post.id} post={post} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default LatestNews;
|
||||
@ -19,6 +19,7 @@ const Navbar = () => {
|
||||
|
||||
<div className={`nav-links ${isOpen ? 'active' : ''}`}>
|
||||
<Link to="/about" onClick={toggleMenu}>회사소개</Link>
|
||||
<Link to="/platform" onClick={toggleMenu}>플랫폼</Link>
|
||||
<Link to="/services" onClick={toggleMenu}>서비스</Link>
|
||||
<Link to="/cases" onClick={toggleMenu}>사례</Link>
|
||||
<Link to="/news" onClick={toggleMenu}>소식</Link>
|
||||
|
||||
19
src/components/Process.jsx
Normal file
19
src/components/Process.jsx
Normal file
@ -0,0 +1,19 @@
|
||||
const Process = () => {
|
||||
return (
|
||||
<section className="section-padding bg-light">
|
||||
<div className="container">
|
||||
<h2 className="section-title">진행 프로세스</h2>
|
||||
<div className="process-grid">
|
||||
{['진단', '설계', '실행', '정착', '고도화'].map((step, index) => (
|
||||
<div key={index} className="process-step-card">
|
||||
<div className="process-step-number">{index + 1}</div>
|
||||
<h3>{step}</h3>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Process;
|
||||
69
src/components/ServiceCurriculum.jsx
Normal file
69
src/components/ServiceCurriculum.jsx
Normal file
@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
|
||||
const ServiceCurriculum = ({ onDownloadGuide }) => {
|
||||
return (
|
||||
<div className="service-section">
|
||||
<h2 className="section-label">
|
||||
Sokuree Consultant<br />교육과정
|
||||
</h2>
|
||||
<p className="section-desc">현장 전문가로 성장할 수 있는 다양한 교육 과정을 경험해보세요.</p>
|
||||
|
||||
<div className="curriculum-grid">
|
||||
|
||||
{/* Col 1 */}
|
||||
<div className="curriculum-card">
|
||||
<span className="curriculum-number">01</span>
|
||||
<h3 className="curriculum-title">경영시스템<br />요구사항 해설</h3>
|
||||
<ul className="curriculum-list">
|
||||
<li><span className="curriculum-bullet">•</span> ISO 9001 (품질)</li>
|
||||
<li><span className="curriculum-bullet">•</span> ISO 14001 (환경)</li>
|
||||
<li><span className="curriculum-bullet">•</span> ISO 45001 (안전보건)</li>
|
||||
<li><span className="curriculum-bullet">•</span> 시스템 문서화 실무</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 2 */}
|
||||
<div className="curriculum-card">
|
||||
<span className="curriculum-number">02</span>
|
||||
<h3 className="curriculum-title">내부심사원<br />양성 과정</h3>
|
||||
<ul className="curriculum-list">
|
||||
<li><span className="curriculum-bullet">•</span> 심사 기법 및 절차</li>
|
||||
<li><span className="curriculum-bullet">•</span> 체크리스트 작성</li>
|
||||
<li><span className="curriculum-bullet">•</span> 부적합 보고서 작성</li>
|
||||
<li><span className="curriculum-bullet">•</span> Role-Play 실습</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 3 */}
|
||||
<div className="curriculum-card">
|
||||
<span className="curriculum-number">03</span>
|
||||
<h3 className="curriculum-title">IATF 16949<br />Core Tools</h3>
|
||||
<ul className="curriculum-list">
|
||||
<li><span className="curriculum-bullet">•</span> APQP / PPAP</li>
|
||||
<li><span className="curriculum-bullet">•</span> FMEA (고장모드)</li>
|
||||
<li><span className="curriculum-bullet">•</span> SPC (통계적공정)</li>
|
||||
<li><span className="curriculum-bullet">•</span> MSA (측정분석)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 4 */}
|
||||
<div className="curriculum-card" style={{ justifyContent: 'space-between' }}>
|
||||
<div>
|
||||
<span className="curriculum-number">04</span>
|
||||
<h3 className="curriculum-title">교육문의 및<br />신청안내</h3>
|
||||
<ul className="curriculum-list">
|
||||
<li>총 32개 과정 운영 중</li>
|
||||
<li>맞춤형 출장 교육 가능</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button className="curriculum-btn" onClick={onDownloadGuide}>
|
||||
<span style={{ fontSize: '1.2rem' }}>📥</span> 교육안내서 보기
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServiceCurriculum;
|
||||
35
src/components/ServicePurpose.jsx
Normal file
35
src/components/ServicePurpose.jsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
|
||||
const ServicePurpose = () => {
|
||||
return (
|
||||
<div className="service-section">
|
||||
<h2 className="section-label">교육 목적</h2>
|
||||
<p className="section-desc">현장 중심의 실무형 인재 양성을 목표로 하고 있어요.</p>
|
||||
|
||||
<div className="purpose-grid">
|
||||
{/* Purpose Card 1 */}
|
||||
<div className="purpose-card">
|
||||
<h3 className="purpose-card-title">스마트 제조 혁신 지원</h3>
|
||||
<p className="purpose-card-text">중소기업의 스마트한<br />제조 환경 구축을 돕습니다.</p>
|
||||
<div className="purpose-icon">🏭</div>
|
||||
</div>
|
||||
|
||||
{/* Purpose Card 2 */}
|
||||
<div className="purpose-card">
|
||||
<h3 className="purpose-card-title">분야별 기술전문가 양성</h3>
|
||||
<p className="purpose-card-text">전문 기술 역량 강화를 통한<br />핵심 인재 육성</p>
|
||||
<div className="purpose-icon">👥</div>
|
||||
</div>
|
||||
|
||||
{/* Purpose Card 3 */}
|
||||
<div className="purpose-card">
|
||||
<h3 className="purpose-card-title">현장 중심 실무 학습</h3>
|
||||
<p className="purpose-card-text">이론과 실무를 겸비한<br />맞춤형 커리큘럼</p>
|
||||
<div className="purpose-icon">📘</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServicePurpose;
|
||||
28
src/components/WhyUs.jsx
Normal file
28
src/components/WhyUs.jsx
Normal file
@ -0,0 +1,28 @@
|
||||
const WhyUs = () => {
|
||||
return (
|
||||
<section className="section-padding">
|
||||
<div className="container">
|
||||
<h2 className="section-title">Why Sokuree?</h2>
|
||||
<div className="solutions-grid" style={{ gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))' }}>
|
||||
<div className="solution-card">
|
||||
<div className="solution-icon">🏆</div>
|
||||
<h3>전문성</h3>
|
||||
<p>품질/ISO 기반의 검증된 컨설팅</p>
|
||||
</div>
|
||||
<div className="solution-card">
|
||||
<div className="solution-icon">🏭</div>
|
||||
<h3>현장 중심</h3>
|
||||
<p>제조 현장에 최적화된 맞춤형 솔루션</p>
|
||||
</div>
|
||||
<div className="solution-card">
|
||||
<div className="solution-icon">🚀</div>
|
||||
<h3>실행력</h3>
|
||||
<p>데이터 시스템의 실질적 구현과 안착</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default WhyUs;
|
||||
@ -1,29 +1,11 @@
|
||||
import consultantProfile from '../assets/consultant_profile.webp';
|
||||
import AboutIntro from '../components/About';
|
||||
|
||||
const About = () => {
|
||||
return (
|
||||
<div className="container" style={{ marginTop: '70px', minHeight: '80vh' }}>
|
||||
{/* Intro Section with Background */}
|
||||
<section className="about-hero">
|
||||
<h1 className="section-title" style={{ marginBottom: '30px' }}>회사 소개</h1>
|
||||
<div className="about-intro">
|
||||
<p>
|
||||
Sokuree Consultant는 현장의 목소리(데이터)에서 필요한 정보를 <br className="hidden md:block" />
|
||||
시스템(System)화 하여 기업의 지속 가능한 성장을 지원합니다.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="vision-mission-grid">
|
||||
<div className="vision-card">
|
||||
<h3>Vision</h3>
|
||||
<p>누구나 쉽게 스마트 경영을 실현하는 세상</p>
|
||||
</div>
|
||||
<div className="vision-card">
|
||||
<h3>Mission</h3>
|
||||
<p>복잡한 기술을 현장에 맞게 단순화하고, 실질적인 성과를 창출하는 것</p>
|
||||
</div>
|
||||
</section>
|
||||
<AboutIntro />
|
||||
|
||||
<section className="expert-profile">
|
||||
<h2 className="section-title">대표 컨설턴트</h2>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import CaseItem from '../components/CaseItem';
|
||||
|
||||
|
||||
const Cases = () => {
|
||||
@ -49,41 +50,7 @@ const Cases = () => {
|
||||
|
||||
<div className="cases-grid">
|
||||
{caseStudies.map(study => (
|
||||
<div key={study.id} className="case-card">
|
||||
{/* Image Section */}
|
||||
{study.image ? (
|
||||
<div className="case-image-wrapper">
|
||||
<img
|
||||
src={study.image}
|
||||
alt={study.title}
|
||||
className="case-image"
|
||||
/>
|
||||
<div className="case-category-badge">
|
||||
{study.category.split('/')[0]}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="case-bar"></div>
|
||||
)}
|
||||
|
||||
{/* Content Section */}
|
||||
<div className="case-content">
|
||||
{!study.image && (
|
||||
<div className="case-category-text">
|
||||
{study.category}
|
||||
</div>
|
||||
)}
|
||||
<h3 className="case-card-title">{study.title}</h3>
|
||||
<div>
|
||||
<span className="case-result-badge">
|
||||
성과: {study.result}
|
||||
</span>
|
||||
</div>
|
||||
<p className="case-details">
|
||||
{study.details}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<CaseItem key={study.id} study={study} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,112 +1,23 @@
|
||||
import Hero from '../components/Hero';
|
||||
import Solutions from '../components/Solutions';
|
||||
import Contact from '../components/Contact';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { usePosts } from '../hooks/usePosts';
|
||||
import PostCard from '../components/PostCard';
|
||||
import WhyUs from '../components/WhyUs';
|
||||
import Process from '../components/Process';
|
||||
import CasesPreview from '../components/CasesPreview';
|
||||
import LatestNews from '../components/LatestNews';
|
||||
|
||||
const Home = () => {
|
||||
return (
|
||||
<>
|
||||
<Hero />
|
||||
|
||||
{/* Why Us Section */}
|
||||
<section className="section-padding">
|
||||
<div className="container">
|
||||
<h2 className="section-title">Why Sokuree?</h2>
|
||||
<div className="solutions-grid" style={{ gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))' }}>
|
||||
<div className="solution-card">
|
||||
<div className="solution-icon">🏆</div>
|
||||
<h3>전문성</h3>
|
||||
<p>품질/ISO 기반의 검증된 컨설팅</p>
|
||||
</div>
|
||||
<div className="solution-card">
|
||||
<div className="solution-icon">🏭</div>
|
||||
<h3>현장 중심</h3>
|
||||
<p>제조 현장에 최적화된 맞춤형 솔루션</p>
|
||||
</div>
|
||||
<div className="solution-card">
|
||||
<div className="solution-icon">🚀</div>
|
||||
<h3>실행력</h3>
|
||||
<p>데이터 시스템의 실질적 구현과 안착</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<WhyUs />
|
||||
<Solutions />
|
||||
|
||||
{/* Process Section */}
|
||||
<section className="section-padding bg-light">
|
||||
<div className="container">
|
||||
<h2 className="section-title">진행 프로세스</h2>
|
||||
<div className="process-grid">
|
||||
{['진단', '설계', '실행', '정착', '고도화'].map((step, index) => (
|
||||
<div key={index} className="process-step-card">
|
||||
<div className="process-step-number">{index + 1}</div>
|
||||
<h3>{step}</h3>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Cases Preview */}
|
||||
<section className="section-padding">
|
||||
<div className="container">
|
||||
<h2 className="section-title">성공 사례</h2>
|
||||
<div className="solutions-grid">
|
||||
<div className="solution-card">
|
||||
<h3>H사 스마트공장 구축</h3>
|
||||
<p>생산성 30% 향상, 불량률 50% 감소</p>
|
||||
</div>
|
||||
<div className="solution-card">
|
||||
<h3>D사 ISO 인증 획득</h3>
|
||||
<p>내부 심사원 양성 및 프로세스 정립</p>
|
||||
</div>
|
||||
<div className="solution-card">
|
||||
<h3>K사 그룹웨어 도입</h3>
|
||||
<p>재고 관리 자동화 및 업무 효율화</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ textAlign: 'center', marginTop: '40px' }}>
|
||||
<Link to="/cases" className="btn btn-primary">사례 더 보기</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Latest News Section */}
|
||||
<LatestNewsSection />
|
||||
|
||||
<Process />
|
||||
<CasesPreview />
|
||||
<LatestNews />
|
||||
<Contact />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const LatestNewsSection = () => {
|
||||
const { posts, loading, error } = usePosts(1, 3); // Fetch 3 latest posts
|
||||
|
||||
if (loading) return null;
|
||||
if (error) return null;
|
||||
if (posts.length === 0) return null;
|
||||
|
||||
return (
|
||||
<section className="section-padding bg-light">
|
||||
<div className="container">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<h2 className="section-title mb-0">최신 소식</h2>
|
||||
<Link to="/news" className="text-primary font-semibold hover:underline">
|
||||
전체 보기 →
|
||||
</Link>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{posts.map((post) => (
|
||||
<PostCard key={post.id} post={post} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
||||
|
||||
@ -3,6 +3,13 @@ import { useParams, Link } from 'react-router-dom';
|
||||
import { wpApi } from '../api/wordpress';
|
||||
|
||||
|
||||
// Helper to handle raw markdown formatting if present
|
||||
const formatContent = (htmlContent) => {
|
||||
if (!htmlContent) return '';
|
||||
// Replace **text** with <strong>text</strong> (Basic bold support)
|
||||
return htmlContent.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
||||
};
|
||||
|
||||
const NewsDetail = () => {
|
||||
const { slug } = useParams();
|
||||
const [post, setPost] = useState(null);
|
||||
@ -81,7 +88,7 @@ const NewsDetail = () => {
|
||||
{/* Content */}
|
||||
<div
|
||||
className="article-content"
|
||||
dangerouslySetInnerHTML={{ __html: post.content.rendered }}
|
||||
dangerouslySetInnerHTML={{ __html: formatContent(post.content.rendered) }}
|
||||
/>
|
||||
|
||||
{/* Footer / Navigation */}
|
||||
|
||||
141
src/pages/Platform.jsx
Normal file
141
src/pages/Platform.jsx
Normal file
@ -0,0 +1,141 @@
|
||||
import React from 'react';
|
||||
import '../styles/main.css';
|
||||
import smartAssetImage from '../assets/214742.png';
|
||||
|
||||
const Platform = () => {
|
||||
return (
|
||||
<div className="service-container">
|
||||
{/* Header Section */}
|
||||
<div className="service-header" style={{ paddingBottom: '3rem' }}>
|
||||
<h1 className="service-title">플랫폼</h1>
|
||||
<p className="service-subtitle">
|
||||
소쿠리 컨설턴트의 혁신적인 솔루션을 만나보세요.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="service-content-wrapper">
|
||||
|
||||
{/* On-premise Solution Section (Moved to Top) */}
|
||||
<div className="service-section" style={{ marginBottom: '8rem' }}>
|
||||
<h2 className="section-label text-center" style={{ textAlign: 'center' }}>구축형 서버 기반 중소기업 스마트 솔루션</h2>
|
||||
<div className="title-underline" style={{ width: '60px', height: '4px', backgroundColor: '#4A628A', margin: '0 auto 3rem' }}></div>
|
||||
|
||||
<div className="content-wrapper" style={{ width: '100%', textAlign: 'center' }}>
|
||||
{/* Reduced fontSize from 1.125rem to 1rem for better line breaks */}
|
||||
<p style={{ fontSize: '1rem', lineHeight: '1.8', color: '#475569', marginBottom: '4rem', maxWidth: '900px', margin: '0 auto 4rem', wordBreak: 'keep-all' }}>
|
||||
중소기업 환경에 최적화된 구축형 서버 기반 스마트 솔루션은 합리적인 비용으로 안정성, 보안성, 확장성을 동시에 제공합니다.<br className="hidden md:block" />
|
||||
기업의 규모와 업무 특성에 맞춰 자유롭게 설계·운영할 수 있는 자체 인프라를 통해 지속 가능한 디지털 경쟁력을 확보할 수 있습니다.
|
||||
</p>
|
||||
|
||||
<div className="features-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', gap: '2rem', textAlign: 'left' }}>
|
||||
{/* Feature 1 */}
|
||||
<div className="feature-item" style={{ padding: '2.5rem', backgroundColor: '#fff', borderRadius: '1rem', border: '1px solid #cbd5e1', boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)' }}>
|
||||
{/* Reduced fontSize from 1.4rem to 1.25rem */}
|
||||
<h4 style={{ fontWeight: 'bold', marginBottom: '1.2rem', color: '#4A628A', fontSize: '1.25rem' }}>자체 서버 구축</h4>
|
||||
{/* Reduced fontSize from 1rem to 0.95rem */}
|
||||
<ul style={{ paddingLeft: '1.2rem', color: '#475569', lineHeight: '1.8', fontSize: '0.85rem' }}>
|
||||
<li>외부 클라우드 의존 없이 사내 인프라 직접 운영</li>
|
||||
<li>기업 데이터에 대한 완전한 통제 및 보안 강화</li>
|
||||
<li>고객 정보·기술 자료·업무 데이터의 안전한 관리</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Feature 2 */}
|
||||
<div className="feature-item" style={{ padding: '2.5rem', backgroundColor: '#fff', borderRadius: '1rem', border: '1px solid #cbd5e1', boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)' }}>
|
||||
<h4 style={{ fontWeight: 'bold', marginBottom: '1.2rem', color: '#4A628A', fontSize: '1.25rem' }}>맞춤형 그룹웨어 운영</h4>
|
||||
<ul style={{ paddingLeft: '1.2rem', color: '#475569', lineHeight: '1.8', fontSize: '0.85rem' }}>
|
||||
<li>전자결재, 문서관리, 일정·프로젝트 관리 통합</li>
|
||||
<li>조직 구조와 업무 방식에 맞춘 자유로운 구성</li>
|
||||
<li>불필요한 기능 제거, 필요한 기능만 선택 도입</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Feature 3 */}
|
||||
<div className="feature-item" style={{ padding: '2.5rem', backgroundColor: '#fff', borderRadius: '1rem', border: '1px solid #cbd5e1', boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)' }}>
|
||||
<h4 style={{ fontWeight: 'bold', marginBottom: '1.2rem', color: '#4A628A', fontSize: '1.25rem' }}>기업 맞춤 업무 시스템 확장</h4>
|
||||
<ul style={{ paddingLeft: '1.2rem', color: '#475569', lineHeight: '1.8', fontSize: '0.85rem' }}>
|
||||
<li>품질/생산관리, 재고관리 등 단계적 구축</li>
|
||||
<li>웹 서비스·데이터베이스·업무 시스템 통합 운영</li>
|
||||
<li>외주·상용 솔루션 종속 없는 자립형 구조</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Feature 4 */}
|
||||
<div className="feature-item" style={{ padding: '2.5rem', backgroundColor: '#fff', borderRadius: '1rem', border: '1px solid #cbd5e1', boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)' }}>
|
||||
<h4 style={{ fontWeight: 'bold', marginBottom: '1.2rem', color: '#4A628A', fontSize: '1.25rem' }}>안정적인 운영과 관리 편의성</h4>
|
||||
<ul style={{ paddingLeft: '1.2rem', color: '#475569', lineHeight: '1.8', fontSize: '0.85rem' }}>
|
||||
<li>웹 기반 관리 환경으로 손쉬운 서버 운영</li>
|
||||
<li>자동 백업, 장애 알림, 신속한 복구 체계</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Feature 5 */}
|
||||
<div className="feature-item" style={{ padding: '2.5rem', backgroundColor: '#fff', borderRadius: '1rem', border: '1px solid #cbd5e1', boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)' }}>
|
||||
<h4 style={{ fontWeight: 'bold', marginBottom: '1.2rem', color: '#4A628A', fontSize: '1.25rem' }}>무한한 확장 가능성</h4>
|
||||
<ul style={{ paddingLeft: '1.2rem', color: '#475569', lineHeight: '1.8', fontSize: '0.85rem' }}>
|
||||
<li>소규모 도입 후 단계적 확장 가능</li>
|
||||
<li>사용자·서비스 증가에 유연하게 대응</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="conclusion-box" style={{ marginTop: '4rem', padding: '2.5rem', backgroundColor: '#f1f5f9', borderRadius: '1rem', borderLeft: '5px solid #4A628A', textAlign: 'left' }}>
|
||||
<p style={{ fontSize: '1.05rem', lineHeight: '1.8', color: '#334155', margin: 0, fontWeight: '500', wordBreak: 'keep-all' }}>
|
||||
구축형 서버 기반 스마트 솔루션은 단순한 시스템 도입이 아닌, 기업 운영 방식에 최적화된 디지털 기반을 직접 설계하는 전략적 선택입니다.<br />
|
||||
중소기업의 현재와 미래를 모두 고려한 현실적인 스마트 인프라 해답을 제시합니다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Smart Asset Section (Moved to Bottom) */}
|
||||
<div className="service-section">
|
||||
<h2 className="section-label text-center" style={{ textAlign: 'center' }}>Smart Asset 모듈</h2>
|
||||
<div className="title-underline" style={{ width: '60px', height: '4px', backgroundColor: '#4A628A', margin: '0 auto 3rem' }}></div>
|
||||
|
||||
<div className="smart-asset-container" style={{ display: 'flex', flexDirection: 'column', gap: '3rem' }}>
|
||||
|
||||
{/* Image Wrapper - Inside Container, Matching Header Width */}
|
||||
<div className="image-wrapper" style={{ width: '100%', display: 'flex', justifyContent: 'center' }}>
|
||||
<img
|
||||
src={smartAssetImage}
|
||||
alt="Smart Asset Module Interface"
|
||||
style={{
|
||||
maxWidth: '100%',
|
||||
height: 'auto',
|
||||
display: 'block'
|
||||
/* No shadow/border as requested */
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="content-wrapper" style={{ width: '100%', textAlign: 'center' }}>
|
||||
|
||||
{/* Features Grid - Updated font sizes for consistency if needed, but original request was specifically about the text overflowing width */}
|
||||
{/* User mainly complained about the new section text exceeding width. But for consistency, let's keep these as they were or slightly adjust if they look too big.
|
||||
Given the request context, I will slightly reduce these too for visual balance. */}
|
||||
<div className="features-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: '1.5rem', textAlign: 'left' }}>
|
||||
<div className="feature-item" style={{ padding: '2rem', backgroundColor: '#fff', borderRadius: '1rem', border: '1px solid #cbd5e1', boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)' }}>
|
||||
<h4 style={{ fontWeight: 'bold', marginBottom: '1rem', color: '#4A628A', fontSize: '1.15rem' }}>자산 현황 파악</h4>
|
||||
<p style={{ fontSize: '0.85rem', color: '#475569', lineHeight: '1.6' }}>실시간으로 자산을 추적하고 관리합니다.</p>
|
||||
</div>
|
||||
<div className="feature-item" style={{ padding: '2rem', backgroundColor: '#fff', borderRadius: '1rem', border: '1px solid #cbd5e1', boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)' }}>
|
||||
<h4 style={{ fontWeight: 'bold', marginBottom: '1rem', color: '#4A628A', fontSize: '1.15rem' }}>이력 관리</h4>
|
||||
<p style={{ fontSize: '0.85rem', color: '#475569', lineHeight: '1.6' }}>구입부터 폐기까지 자산의 이력을 기록합니다.</p>
|
||||
</div>
|
||||
<div className="feature-item" style={{ padding: '2rem', backgroundColor: '#fff', borderRadius: '1rem', border: '1px solid #cbd5e1', boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)' }}>
|
||||
<h4 style={{ fontWeight: 'bold', marginBottom: '1rem', color: '#4A628A', fontSize: '1.15rem' }}>효율성 증대</h4>
|
||||
<p style={{ fontSize: '0.85rem', color: '#475569', lineHeight: '1.6' }}>체계적인 데이터 관리로 업무 효율성을 극대화합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Platform;
|
||||
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import ServicePurpose from '../components/ServicePurpose';
|
||||
import ServiceCurriculum from '../components/ServiceCurriculum';
|
||||
|
||||
const ServiceDetail = () => {
|
||||
const navigate = useNavigate();
|
||||
@ -26,97 +28,10 @@ const ServiceDetail = () => {
|
||||
<div className="service-content-wrapper">
|
||||
|
||||
{/* Section 1: Education Purpose (3 Cards) */}
|
||||
<div className="service-section">
|
||||
<h2 className="section-label">교육 목적</h2>
|
||||
<p className="section-desc">현장 중심의 실무형 인재 양성을 목표로 하고 있어요.</p>
|
||||
|
||||
<div className="purpose-grid">
|
||||
{/* Purpose Card 1 */}
|
||||
<div className="purpose-card">
|
||||
<h3 className="purpose-card-title">스마트 제조 혁신 지원</h3>
|
||||
<p className="purpose-card-text">중소기업의 스마트한<br />제조 환경 구축을 돕습니다.</p>
|
||||
<div className="purpose-icon">🏭</div>
|
||||
</div>
|
||||
|
||||
{/* Purpose Card 2 */}
|
||||
<div className="purpose-card">
|
||||
<h3 className="purpose-card-title">분야별 기술전문가 양성</h3>
|
||||
<p className="purpose-card-text">전문 기술 역량 강화를 통한<br />핵심 인재 육성</p>
|
||||
<div className="purpose-icon">👥</div>
|
||||
</div>
|
||||
|
||||
{/* Purpose Card 3 */}
|
||||
<div className="purpose-card">
|
||||
<h3 className="purpose-card-title">현장 중심 실무 학습</h3>
|
||||
<p className="purpose-card-text">이론과 실무를 겸비한<br />맞춤형 커리큘럼</p>
|
||||
<div className="purpose-icon">📘</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ServicePurpose />
|
||||
|
||||
{/* Section 2: Curriculum (4 Numbered Columns) */}
|
||||
<div className="service-section">
|
||||
<h2 className="section-label">
|
||||
Sokuree Consultant<br />교육과정
|
||||
</h2>
|
||||
<p className="section-desc">현장 전문가로 성장할 수 있는 다양한 교육 과정을 경험해보세요.</p>
|
||||
|
||||
<div className="curriculum-grid">
|
||||
|
||||
{/* Col 1 */}
|
||||
<div className="curriculum-card">
|
||||
<span className="curriculum-number">01</span>
|
||||
<h3 className="curriculum-title">경영시스템<br />요구사항 해설</h3>
|
||||
<ul className="curriculum-list">
|
||||
<li><span className="curriculum-bullet">•</span> ISO 9001 (품질)</li>
|
||||
<li><span className="curriculum-bullet">•</span> ISO 14001 (환경)</li>
|
||||
<li><span className="curriculum-bullet">•</span> ISO 45001 (안전보건)</li>
|
||||
<li><span className="curriculum-bullet">•</span> 시스템 문서화 실무</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 2 */}
|
||||
<div className="curriculum-card">
|
||||
<span className="curriculum-number">02</span>
|
||||
<h3 className="curriculum-title">내부심사원<br />양성 과정</h3>
|
||||
<ul className="curriculum-list">
|
||||
<li><span className="curriculum-bullet">•</span> 심사 기법 및 절차</li>
|
||||
<li><span className="curriculum-bullet">•</span> 체크리스트 작성</li>
|
||||
<li><span className="curriculum-bullet">•</span> 부적합 보고서 작성</li>
|
||||
<li><span className="curriculum-bullet">•</span> Role-Play 실습</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 3 */}
|
||||
<div className="curriculum-card">
|
||||
<span className="curriculum-number">03</span>
|
||||
<h3 className="curriculum-title">IATF 16949<br />Core Tools</h3>
|
||||
<ul className="curriculum-list">
|
||||
<li><span className="curriculum-bullet">•</span> APQP / PPAP</li>
|
||||
<li><span className="curriculum-bullet">•</span> FMEA (고장모드)</li>
|
||||
<li><span className="curriculum-bullet">•</span> SPC (통계적공정)</li>
|
||||
<li><span className="curriculum-bullet">•</span> MSA (측정분석)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Col 4 */}
|
||||
<div className="curriculum-card" style={{ justifyContent: 'space-between' }}>
|
||||
<div>
|
||||
<span className="curriculum-number">04</span>
|
||||
<h3 className="curriculum-title">교육문의 및<br />신청안내</h3>
|
||||
<ul className="curriculum-list">
|
||||
<li>총 32개 과정 운영 중</li>
|
||||
<li>맞춤형 출장 교육 가능</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button className="curriculum-btn" onClick={handleDownloadGuide}>
|
||||
<span style={{ fontSize: '1.2rem' }}>📥</span> 교육안내서 보기
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<ServiceCurriculum onDownloadGuide={handleDownloadGuide} />
|
||||
|
||||
{/* Bottom CTA Banner */}
|
||||
<div className="cta-banner">
|
||||
|
||||
@ -67,7 +67,6 @@ img {
|
||||
-khtml-user-drag: none;
|
||||
-moz-user-drag: none;
|
||||
-o-user-drag: none;
|
||||
user-drag: none;
|
||||
pointer-events: none;
|
||||
/* Prevents right-click context menu on images */
|
||||
}
|
||||
@ -1327,7 +1326,7 @@ img {
|
||||
|
||||
.news-article {
|
||||
background-color: var(--white);
|
||||
max-width: 800px;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
margin: 0 20px;
|
||||
padding: 3rem;
|
||||
@ -1374,6 +1373,16 @@ img {
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: var(--light-gray);
|
||||
/* Optional: background for transparent images */
|
||||
}
|
||||
|
||||
.article-image {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* ... NewsDetail content styles ... */
|
||||
@ -1473,4 +1482,138 @@ img {
|
||||
border-color: var(--primary-color);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* =========================================
|
||||
6. ARTICLE CONTENT STYLES (WordPress)
|
||||
========================================= */
|
||||
.article-content {
|
||||
line-height: 1.8;
|
||||
color: var(--text-color);
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.article-content p {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.article-content h1,
|
||||
.article-content h2,
|
||||
.article-content h3,
|
||||
.article-content h4,
|
||||
.article-content h5,
|
||||
.article-content h6 {
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.article-content h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.article-content h2 {
|
||||
font-size: 1.75rem;
|
||||
border-bottom: 2px solid var(--border-color);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.article-content h3 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.article-content h4 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.article-content h5 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.article-content h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.article-content ul,
|
||||
.article-content ol {
|
||||
margin-bottom: 1.5rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.article-content ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.article-content ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
.article-content li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.article-content strong,
|
||||
.article-content b {
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.article-content a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.article-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
margin: 2rem 0;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.article-content blockquote {
|
||||
border-left: 4px solid var(--primary-color);
|
||||
padding: 1rem;
|
||||
margin: 1.5rem 0;
|
||||
background-color: var(--light-gray);
|
||||
border-radius: 0 8px 8px 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Helper Classes for Alignments */
|
||||
.article-content .aligncenter {
|
||||
display: block;
|
||||
margin: 0 auto 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.article-content .alignright {
|
||||
float: right;
|
||||
margin-left: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.article-content .alignleft {
|
||||
float: left;
|
||||
margin-right: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* Gutenberg Text Alignment */
|
||||
.article-content .has-text-align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.article-content .has-text-align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.article-content .has-text-align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.article-content .has-text-align-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user