feat(tactical): enhance symbols palette, instructions, and fix header layout spacing
This commit is contained in:
@@ -229,7 +229,14 @@ export const TacticalDefenseView: React.FC = () => {
|
|||||||
// Tactical Symbols Layer
|
// Tactical Symbols Layer
|
||||||
initialMap.addSource('tactical-symbols-src', {
|
initialMap.addSource('tactical-symbols-src', {
|
||||||
type: 'geojson',
|
type: 'geojson',
|
||||||
data: { type: 'FeatureCollection', features: [] }
|
data: {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: DEFAULT_SYMBOLS.map(s => ({
|
||||||
|
type: 'Feature',
|
||||||
|
properties: { type: s.type, name: s.name },
|
||||||
|
geometry: { type: 'Point', coordinates: [s.lng, s.lat] }
|
||||||
|
})) as any
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
initialMap.addLayer({
|
initialMap.addLayer({
|
||||||
@@ -247,6 +254,7 @@ export const TacticalDefenseView: React.FC = () => {
|
|||||||
'radar', '#06b6d4',
|
'radar', '#06b6d4',
|
||||||
'checkpoint', '#eab308',
|
'checkpoint', '#eab308',
|
||||||
'minefield', '#dc2626',
|
'minefield', '#dc2626',
|
||||||
|
'hlz', '#10b981',
|
||||||
'#a855f7'
|
'#a855f7'
|
||||||
],
|
],
|
||||||
'circle-stroke-color': '#ffffff',
|
'circle-stroke-color': '#ffffff',
|
||||||
@@ -433,22 +441,23 @@ export const TacticalDefenseView: React.FC = () => {
|
|||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
background: '#0a0e17',
|
background: '#0a0e17',
|
||||||
color: '#f8fafc',
|
color: '#f8fafc',
|
||||||
fontFamily: "'IBM Plex Sans Arabic', Inter, system-ui, sans-serif",
|
fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "SF Pro Arabic", system-ui, sans-serif',
|
||||||
direction: 'rtl',
|
direction: 'rtl',
|
||||||
overflow: 'hidden'
|
overflow: 'hidden',
|
||||||
|
paddingTop: 56
|
||||||
}}>
|
}}>
|
||||||
{/* Top Military HUD Header */}
|
{/* Top Military HUD Header */}
|
||||||
<header style={{
|
<header style={{
|
||||||
height: 54,
|
height: 52,
|
||||||
background: 'rgba(11, 15, 25, 0.95)',
|
background: '#0f172a',
|
||||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
borderBottom: '1px solid #1e293b',
|
||||||
backdropFilter: 'blur(16px)',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
padding: '0 20px',
|
padding: '0 18px',
|
||||||
zIndex: 100,
|
zIndex: 50,
|
||||||
gap: 16
|
gap: 14,
|
||||||
|
flexShrink: 0
|
||||||
}}>
|
}}>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
@@ -847,6 +856,18 @@ export const TacticalDefenseView: React.FC = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style={{
|
||||||
|
background: 'rgba(168, 85, 247, 0.12)',
|
||||||
|
border: '1px solid rgba(168, 85, 247, 0.3)',
|
||||||
|
padding: '8px 10px',
|
||||||
|
borderRadius: 8,
|
||||||
|
fontSize: '0.78rem',
|
||||||
|
color: '#e9d5ff',
|
||||||
|
lineHeight: 1.4
|
||||||
|
}}>
|
||||||
|
🎯 <strong>طريقة التثبيت:</strong> اختر نوع الرمز واسم الوحدة، ثم <strong>انقر على أي نقطة بالخريطة</strong> لإسقاطه فوراً وتثبيت إحداثياته.
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label style={{ fontSize: '0.75rem', color: '#94a3b8', display: 'block', marginBottom: 4 }}>نوع الرمز العسكري:</label>
|
<label style={{ fontSize: '0.75rem', color: '#94a3b8', display: 'block', marginBottom: 4 }}>نوع الرمز العسكري:</label>
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
|
||||||
@@ -854,22 +875,26 @@ export const TacticalDefenseView: React.FC = () => {
|
|||||||
{ id: 'friendly', label: '🟦 وحدة صديقة' },
|
{ id: 'friendly', label: '🟦 وحدة صديقة' },
|
||||||
{ id: 'hostile', label: '🟥 هدف معادي' },
|
{ id: 'hostile', label: '🟥 هدف معادي' },
|
||||||
{ id: 'artillery', label: '🟧 مربض مدفعية' },
|
{ id: 'artillery', label: '🟧 مربض مدفعية' },
|
||||||
{ id: 'radar', label: '🟦 محطة رادار' },
|
{ id: 'radar', label: '🩵 محطة رادار' },
|
||||||
{ id: 'checkpoint', label: '🟨 نقطة سيطرة' },
|
{ id: 'checkpoint', label: '🟨 نقطة سيطرة' },
|
||||||
{ id: 'op', label: '🟪 نقطة مراقبة' },
|
{ id: 'op', label: '🟪 نقطة مراقبة' },
|
||||||
|
{ id: 'minefield', label: '⛔ حقل ألغام' },
|
||||||
|
{ id: 'hlz', label: '🚁 مهبط مروحيات' },
|
||||||
].map(sym => (
|
].map(sym => (
|
||||||
<button
|
<button
|
||||||
key={sym.id}
|
key={sym.id}
|
||||||
onClick={() => setSelectedSymbolType(sym.id)}
|
onClick={() => setSelectedSymbolType(sym.id)}
|
||||||
style={{
|
style={{
|
||||||
background: selectedSymbolType === sym.id ? 'rgba(168, 85, 247, 0.25)' : 'rgba(255,255,255,0.05)',
|
background: selectedSymbolType === sym.id ? 'rgba(168, 85, 247, 0.35)' : 'rgba(255,255,255,0.05)',
|
||||||
border: selectedSymbolType === sym.id ? '1px solid #a855f7' : '1px solid rgba(255,255,255,0.1)',
|
border: selectedSymbolType === sym.id ? '1px solid #c084fc' : '1px solid rgba(255,255,255,0.1)',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
padding: '6px 8px',
|
padding: '6px 8px',
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
fontSize: '0.75rem',
|
fontSize: '0.75rem',
|
||||||
|
fontWeight: selectedSymbolType === sym.id ? 700 : 500,
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
textAlign: 'right'
|
textAlign: 'right',
|
||||||
|
transition: 'all 0.15s ease'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{sym.label}
|
{sym.label}
|
||||||
@@ -882,7 +907,7 @@ export const TacticalDefenseView: React.FC = () => {
|
|||||||
<label style={{ fontSize: '0.75rem', color: '#94a3b8', display: 'block', marginBottom: 4 }}>تسمية الرمز / الوحدة:</label>
|
<label style={{ fontSize: '0.75rem', color: '#94a3b8', display: 'block', marginBottom: 4 }}>تسمية الرمز / الوحدة:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="مثال: سرية الدبابات 1"
|
placeholder="مثال: سرية الدبابات 1 / بطارية صواريخ"
|
||||||
value={newSymbolName}
|
value={newSymbolName}
|
||||||
onChange={e => setNewSymbolName(e.target.value)}
|
onChange={e => setNewSymbolName(e.target.value)}
|
||||||
style={{ width: '100%', background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.15)', color: '#fff', padding: '8px', borderRadius: 8, fontSize: '0.8rem' }}
|
style={{ width: '100%', background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.15)', color: '#fff', padding: '8px', borderRadius: 8, fontSize: '0.8rem' }}
|
||||||
@@ -890,12 +915,30 @@ export const TacticalDefenseView: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Active Symbols List */}
|
{/* Active Symbols List */}
|
||||||
<div style={{ marginTop: 8 }}>
|
<div style={{ marginTop: 4 }}>
|
||||||
<div style={{ fontSize: '0.8rem', color: '#94a3b8', marginBottom: 6 }}>الرموز المنتشرة على الخريطة ({symbols.length}):</div>
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 6 }}>
|
||||||
|
<span style={{ fontSize: '0.8rem', color: '#94a3b8' }}>الرموز المنتشرة ({symbols.length}):</span>
|
||||||
|
{symbols.length > 0 && (
|
||||||
|
<button
|
||||||
|
onClick={() => setSymbols([])}
|
||||||
|
style={{ background: 'none', border: 'none', color: '#ef4444', fontSize: '0.72rem', cursor: 'pointer', textDecoration: 'underline' }}
|
||||||
|
>
|
||||||
|
مسح الكل
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 6, maxHeight: 180, overflowY: 'auto' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 6, maxHeight: 180, overflowY: 'auto' }}>
|
||||||
{symbols.map(s => (
|
{symbols.map(s => (
|
||||||
<div key={s.id} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', background: 'rgba(255,255,255,0.04)', padding: '6px 10px', borderRadius: 6, fontSize: '0.78rem' }}>
|
<div key={s.id} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', background: 'rgba(255,255,255,0.04)', padding: '6px 10px', borderRadius: 6, fontSize: '0.78rem' }}>
|
||||||
<span>{s.name}</span>
|
<span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||||
|
<span style={{
|
||||||
|
width: 8,
|
||||||
|
height: 8,
|
||||||
|
borderRadius: '50%',
|
||||||
|
background: s.type === 'friendly' ? '#3b82f6' : s.type === 'hostile' ? '#ef4444' : s.type === 'artillery' ? '#f97316' : s.type === 'radar' ? '#06b6d4' : s.type === 'checkpoint' ? '#eab308' : s.type === 'minefield' ? '#dc2626' : s.type === 'hlz' ? '#10b981' : '#a855f7'
|
||||||
|
}} />
|
||||||
|
<span>{s.name}</span>
|
||||||
|
</span>
|
||||||
<button
|
<button
|
||||||
onClick={() => setSymbols(symbols.filter(x => x.id !== s.id))}
|
onClick={() => setSymbols(symbols.filter(x => x.id !== s.id))}
|
||||||
style={{ background: 'none', border: 'none', color: '#ef4444', cursor: 'pointer', padding: 2 }}
|
style={{ background: 'none', border: 'none', color: '#ef4444', cursor: 'pointer', padding: 2 }}
|
||||||
|
|||||||
Reference in New Issue
Block a user