בעולם השיווק של B2B בלינקדאין, הרושם הראשוני הוא הכל.
הפיד עמוס בטקסטים אחידים ומשעממים, והדרך היחידה לעצור את הגלילה היא באמצעות ויזואליות חזקה –
גם בתמונה וגם, לפני שבכלל רואים את התמונה, בטקסט עצמו.
ה-LinkedIn Formatter הוא כלי חכם ונוח לשימוש;
שמאפשר לך להוסיף הדגשות (Bold), כתב נטוי (Italic) או שילובים ביניהם לפוסטים שלך באנגלית.
בעזרת הכלי ניתן להפוך טקסט סטנדרטי למסרים שיווקיים ברורים, קריאים ומשכנעים – כאלה שמבליטים את עיקרי הדברים ומשדרים מקצועיות ואמינות.
בין אם אתם מנהלי שיווק, מגייסים או יזמים – עיצוב מדויק של הפוסט יכול להעלות משמעותית את רמת המעורבות ואת שיעורי ההמרה של התוכן שלכם.
@import url('https://fonts.googleapis.com/css2?family=Assistant:wght@300;400;600;700;800&display=swap');
:root {
--primary-blue: #0A66C2;
--dark-text: #1d1d1f;
}
body {
font-family: 'Assistant', sans-serif;
background: transparent;
margin: 0;
padding: 0;
}
.tool-container {
max-width: 1000px;
margin: 0 auto;
}
.glass-card {
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
}
.selection-popup {
transform: translate(-50%, -100%);
margin-top: -12px;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
textarea::placeholder { color: #a1a1a6; }
.step-number {
background: var(--primary-blue);
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
color: white;
font-size: 14px;
font-weight: 700;
}
/* Protection Screen Styles */
.protection-overlay {
position: fixed;
inset: 0;
background: #b91c1c;
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
z-index: 9999;
padding: 20px;
}
const { useState, useRef, useEffect } = React;
const Icon = ({ name, size = 20, className = "" }) => {
useEffect(() => { if (window.lucide) window.lucide.createIcons(); }, []);
return <i data-lucide={name} style={{width: size, height: size}} className={className}></i>;
};
// Unicode math chars generator logic (Bulletproof)
const getStyledChar = (char, mode) => {
const code = char.charCodeAt(0);
if (mode === 'bold') {
if (code >= 65 && code <= 90) return String.fromCodePoint(code - 65 + 0x1D400);
if (code >= 97 && code <= 122) return String.fromCodePoint(code - 97 + 0x1D41A);
if (code >= 48 && code <= 57) return String.fromCodePoint(code - 48 + 0x1D7CE);
}
if (mode === 'italic') {
if (code >= 65 && code <= 90) return String.fromCodePoint(code - 65 + 0x1D434);
if (code >= 97 && code <= 122) {
if (char === 'h') return 'ℎ';
return String.fromCodePoint(code - 97 + 0x1D44E);
}
}
if (mode === 'boldItalic') {
if (code >= 65 && code <= 90) return String.fromCodePoint(code - 65 + 0x1D468);
if (code >= 97 && code <= 122) return String.fromCodePoint(code - 97 + 0x1D482);
}
return char;
};
const transformText = (text, mode) => text.split('').map(c => getStyledChar(c, mode)).join('');
function App() {
const [isAuthorized, setIsAuthorized] = useState(true);
const [input, setInput] = useState('');
const [output, setOutput] = useState('');
const [copied, setCopied] = useState(false);
const [popup, setPopup] = useState({ show: false, x: 0, y: 0 });
const [smartMode, setSmartMode] = useState(true);
const areaRef = useRef(null);
// Domain Security Check
useEffect(() => {
const host = window.location.hostname.toLowerCase();
const allowed = ['amirbaldiga.com', 'localhost', '127.0.0.1'];
const isOk = allowed.some(domain => host.includes(domain));
if (!isOk) {
setIsAuthorized(false);
}
}, []);
useEffect(() => {
let res = input;
if (smartMode && res.trim()) {
let lines = res.split('\n');
lines = lines.map((l, i) => {
if (i === 0 && l.trim()) return transformText(l, 'bold');
const m = l.match(/^([^a-zA-Z]*)([a-zA-Z0-9\s]+?)([:-])(.*)$/);
if (m) return `${m[1]}${transformText(m[2], 'bold')}${m[3]}${m[4]}`;
return l;
});
res = lines.join('\n');
}
res = res.replace(/(\*\*\*|___)(.*?)\1/g, (m, _, p) => transformText(p, 'boldItalic'));
res = res.replace(/\*\*(.*?)\*\*/g, (m, p) => transformText(p, 'bold'));
res = res.replace(/(\*|_)(.*?)\1/g, (m, _, p) => transformText(p, 'italic'));
setOutput(res);
}, [input, smartMode]);
const handleFormat = (syntax) => {
const el = areaRef.current;
const start = el.selectionStart;
const end = el.selectionEnd;
const val = el.value;
const selection = val.substring(start, end) || "text";
setInput(val.substring(0, start) + syntax + selection + syntax + val.substring(end));
setPopup({ ...popup, show: false });
setTimeout(() => el.focus(), 0);
};
const checkSelection = (e) => {
const el = areaRef.current;
if (el.selectionStart !== el.selectionEnd) {
const rect = el.getBoundingClientRect();
setPopup({ show: true, x: e.clientX - rect.left, y: e.clientY - rect.top - 45 });
} else setPopup({ ...popup, show: false });
};
const copy = () => {
const el = document.createElement('textarea');
el.value = output;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
// If domain check fails, return the "Threat" message
if (!isAuthorized) {
return (
<div className="protection-overlay">
<Icon name="shield-alert" size={80} className="mb-6" />
<h1 className="text-4xl font-black mb-4">גישה חסומה</h1>
<p className="text-xl max-w-lg font-bold leading-relaxed">
הפרוייקט הזה הוא מוצר מוגן בזכויות של אמיר בלדיגה.
<br />
הודעה נשלחה לגורמים הרלוונטיים.
</p>
<div className="mt-10 opacity-50 text-sm">amirbaldiga.com © Security Protocol</div>
</div>
);
}
return (
<div className="tool-container space-y-10 py-6 px-4">
{/* Header */}
<div className="text-right space-y-2">
<h2 className="text-3xl font-extrabold text-[#1d1d1f]">LinkedIn Post Formatter</h2>
<p className="text-gray-500 font-medium italic">by Amir Baldiga</p>
</div>
{/* Step-by-Step Instructions */}
<div className="grid md:grid-cols-3 gap-4">
{[
{title: "כתבו באנגלית", desc: "הזינו את הפוסט. הכותרת תודגש אוטומטית."},
{title: "עיצוב ידני", desc: "סמנו מילה עם העכבר לבחירת סגנון נוסף."},
{title: "העתקה", desc: "העתיקו והדביקו ישירות בפוסט בלינקדאין."}
].map((s, i) => (
<div key={i} className="glass-card p-5 flex items-center gap-4">
<div className="step-number shrink-0">{i+1}</div>
<div>
<div className="font-bold text-sm text-gray-800">{s.title}</div>
<div className="text-xs text-gray-500">{s.desc}</div>
</div>
</div>
))}
</div>
<div className="grid lg:grid-cols-2 gap-8">
{/* Editor Area */}
<div className="glass-card overflow-hidden flex flex-col h-[500px] border-none">
<div className="p-4 border-b border-gray-100 flex justify-between items-center bg-white/30">
<span className="text-xs font-bold text-gray-400 uppercase tracking-widest flex items-center gap-2">
<Icon name="pen-tool" size={14} /> עורך התוכן
</span>
<div className="flex items-center gap-3">
<span className="text-[10px] font-bold text-gray-400">SMART MODE</span>
<button onClick={() => setSmartMode(!smartMode)} className={`w-8 h-4 rounded-full relative transition-all ${smartMode ? 'bg-blue-600' : 'bg-gray-300'}`}>
<div className={`absolute top-0.5 w-3 h-3 bg-white rounded-full transition-all ${smartMode ? 'left-4.5' : 'left-0.5'}`} />
</button>
</div>
</div>
<div className="relative flex-1">
<textarea
ref={areaRef}
value={input}
onChange={(e) => setInput(e.target.value)}
onMouseUp={checkSelection}
className="w-full h-full p-8 outline-none bg-transparent text-lg leading-relaxed text-gray-800"
placeholder="Type your strategy here..."
/>
{popup.show && (
<div className="absolute bg-gray-900 text-white rounded-xl flex items-center p-1 gap-1 z-50 selection-popup" style={{ top: popup.y, left: popup.x }}>
<button onClick={() => handleFormat('**')} className="p-2 hover:bg-white/20 rounded-lg"><Icon name="bold" size={16} /></button>
<button onClick={() => handleFormat('_')} className="p-2 hover:bg-white/20 rounded-lg"><Icon name="italic" size={16} /></button>
<button onClick={() => handleFormat('***')} className="px-2 py-1 hover:bg-white/20 rounded-lg text-xs font-serif italic font-bold">BI</button>
</div>
)}
</div>
</div>
{/* Preview Area */}
<div className="glass-card overflow-hidden flex flex-col h-[500px] border-none shadow-xl">
<div className="p-4 border-b border-gray-100 flex justify-between items-center bg-[#0A66C2]">
<span className="text-xs font-bold text-white uppercase tracking-widest flex items-center gap-2">
<Icon name="eye" size={14} /> תצוגה מקדימה
</span>
<button onClick={copy} className={`flex items-center gap-2 px-5 py-1.5 rounded-full text-xs font-bold transition-all ${copied ? 'bg-green-500 text-white' : 'bg-white text-[#0A66C2]'}`}>
<Icon name={copied ? "check" : "copy"} size={14} />
{copied ? 'הועתק!' : 'העתקה ללינקדאין'}
</button>
</div>
<div className="flex-1 p-8 overflow-y-auto bg-white/60 text-lg leading-relaxed text-gray-900 whitespace-pre-wrap">
{output || <div className="text-gray-300 text-center mt-20 italic">התוצאה תופיע כאן...</div>}
</div>
</div>
</div>
<div className="text-center pb-10">
<p className="text-[10px] text-gray-400 font-bold uppercase tracking-widest tracking-[0.2em]">Amir Baldiga • Strategy & Tools</p>
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);