feat: WCAG AA accessibility, code splitting, responsive ads layout
- Add React.lazy code splitting for all 15 tool pages - Fix WCAG AA contrast issues (304 text color fixes) - Add ARIA labels and aria-expanded to navigation buttons - Add aria-live for error announcements in tools - Implement responsive ad layout: - Desktop (≥1280px): Right sidebar with 3 ad units - Tablet (1024-1279px): Bottom section with 3 horizontal units - Mobile (<1024px): Fixed bottom banner - Add TabletAdSection component for tablet ad placement - Integrate Onidel affiliate partnership - Update all Adsterra domains to solutionbiologyisle.com - Add release notes for 2026-02-18 updates
This commit is contained in:
@@ -1863,7 +1863,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-3 text-sm font-medium transition-colors whitespace-nowrap ${
|
||||
activeTab === "create"
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-b-2 border-blue-500"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
@@ -1874,7 +1874,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-3 text-sm font-medium transition-colors whitespace-nowrap ${
|
||||
activeTab === "url"
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-b-2 border-blue-500"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<Globe className="h-4 w-4" />
|
||||
@@ -1885,7 +1885,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-3 text-sm font-medium transition-colors whitespace-nowrap ${
|
||||
activeTab === "paste"
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-b-2 border-blue-500"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<FileText className="h-4 w-4" />
|
||||
@@ -1896,7 +1896,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-3 text-sm font-medium transition-colors whitespace-nowrap ${
|
||||
activeTab === "upload"
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-b-2 border-blue-500"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<Upload className="h-4 w-4" />
|
||||
@@ -1914,7 +1914,7 @@ const TableEditor = () => {
|
||||
<h3 className="text-lg font-medium text-gray-900 dark:text-gray-100 mb-2">
|
||||
Start Building Your Table
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-600 mb-4">
|
||||
Choose how you'd like to begin working with your data
|
||||
</p>
|
||||
</div>
|
||||
@@ -1932,11 +1932,11 @@ const TableEditor = () => {
|
||||
}}
|
||||
className="flex flex-col items-center p-6 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg hover:border-blue-500 dark:hover:border-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors group"
|
||||
>
|
||||
<Plus className="h-8 w-8 text-gray-400 group-hover:text-blue-500 dark:group-hover:text-blue-400 mb-2" />
|
||||
<Plus className="h-8 w-8 text-gray-600 group-hover:text-blue-500 dark:group-hover:text-blue-400 mb-2" />
|
||||
<span className="font-medium text-gray-900 dark:text-gray-100 group-hover:text-blue-600 dark:group-hover:text-blue-400">
|
||||
Start Empty
|
||||
</span>
|
||||
<span className="text-xs text-gray-500 dark:text-gray-400 text-center mt-1">
|
||||
<span className="text-xs text-gray-600 dark:text-gray-600 text-center mt-1">
|
||||
Create a blank table with basic columns
|
||||
</span>
|
||||
</button>
|
||||
@@ -2005,11 +2005,11 @@ const TableEditor = () => {
|
||||
}}
|
||||
className="flex flex-col items-center p-6 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg hover:border-green-500 dark:hover:border-green-400 hover:bg-green-50 dark:hover:bg-green-900/20 transition-colors group"
|
||||
>
|
||||
<FileText className="h-8 w-8 text-gray-400 group-hover:text-green-500 dark:group-hover:text-green-400 mb-2" />
|
||||
<FileText className="h-8 w-8 text-gray-600 group-hover:text-green-500 dark:group-hover:text-green-400 mb-2" />
|
||||
<span className="font-medium text-gray-900 dark:text-gray-100 group-hover:text-green-600 dark:group-hover:text-green-400">
|
||||
Load Sample
|
||||
</span>
|
||||
<span className="text-xs text-gray-500 dark:text-gray-400 text-center mt-1">
|
||||
<span className="text-xs text-gray-600 dark:text-gray-600 text-center mt-1">
|
||||
Start with example data to explore features
|
||||
</span>
|
||||
</button>
|
||||
@@ -2055,7 +2055,7 @@ const TableEditor = () => {
|
||||
{url && !isLoading && (
|
||||
<button
|
||||
onClick={() => setUrl("")}
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 transition-colors"
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-600 hover:text-gray-600 dark:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
@@ -2069,7 +2069,7 @@ const TableEditor = () => {
|
||||
{isLoading ? "Fetching..." : "Fetch Data"}
|
||||
</button>
|
||||
</div>
|
||||
<label className="flex items-center text-sm text-gray-600 dark:text-gray-400">
|
||||
<label className="flex items-center text-sm text-gray-600 dark:text-gray-600">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={useFirstRowAsHeader}
|
||||
@@ -2118,7 +2118,7 @@ const TableEditor = () => {
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-between flex-shrink-0">
|
||||
<label className="flex items-center text-sm text-gray-600 dark:text-gray-400">
|
||||
<label className="flex items-center text-sm text-gray-600 dark:text-gray-600">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={useFirstRowAsHeader}
|
||||
@@ -2161,7 +2161,7 @@ const TableEditor = () => {
|
||||
onChange={handleFileUpload}
|
||||
className="tool-input"
|
||||
/>
|
||||
<label className="flex items-center text-sm text-gray-600 dark:text-gray-400">
|
||||
<label className="flex items-center text-sm text-gray-600 dark:text-gray-600">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={useFirstRowAsHeader}
|
||||
@@ -2204,7 +2204,7 @@ const TableEditor = () => {
|
||||
{availableTables.length > 1 ? "Multi-Table Database" : "Table Editor"}
|
||||
</h3>
|
||||
{availableTables.length === 1 && (
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-600">
|
||||
{data.length} rows, {columns.length} columns
|
||||
</p>
|
||||
)}
|
||||
@@ -2219,7 +2219,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-2 px-3 py-2 text-sm font-medium transition-colors ${
|
||||
isTableFullscreen
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700"
|
||||
}`}
|
||||
>
|
||||
{isTableFullscreen ? (
|
||||
@@ -2233,7 +2233,7 @@ const TableEditor = () => {
|
||||
</button>
|
||||
<button
|
||||
onClick={clearData}
|
||||
className="flex items-center gap-2 px-3 py-2 text-sm font-medium transition-colors border-l border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700"
|
||||
className="flex items-center gap-2 px-3 py-2 text-sm font-medium transition-colors border-l border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700"
|
||||
>
|
||||
<AlertTriangle className="h-4 w-4" />
|
||||
<span className="hidden sm:inline">Clear All</span>
|
||||
@@ -2246,7 +2246,7 @@ const TableEditor = () => {
|
||||
{availableTables.length > 1 && (
|
||||
<div className="px-4 py-3 flex flex-col sm:flex-row items-start sm:items-center gap-3 sm:gap-4 border-b border-gray-200 dark:border-gray-700 justify-between">
|
||||
<div className="flex items-center gap-2 w-full sm:max-w-1/2">
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap hidden sm:inline">
|
||||
<span className="text-sm text-gray-600 dark:text-gray-600 whitespace-nowrap hidden sm:inline">
|
||||
Current Table:
|
||||
</span>
|
||||
<select
|
||||
@@ -2267,7 +2267,7 @@ const TableEditor = () => {
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-600">
|
||||
{data.length} rows, {columns.length} columns
|
||||
</p>
|
||||
</div>
|
||||
@@ -2279,7 +2279,7 @@ const TableEditor = () => {
|
||||
<div className="px-4 py-3 flex flex-col sm:flex-row items-start sm:items-center gap-3 sm:gap-4 border-b border-gray-200 dark:border-gray-700">
|
||||
{/* Search Bar */}
|
||||
<div className="relative w-full">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-600" />
|
||||
<input
|
||||
type="text"
|
||||
value={searchTerm}
|
||||
@@ -2319,7 +2319,7 @@ const TableEditor = () => {
|
||||
|
||||
{/* Freeze Columns Control */}
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs sm:text-sm text-gray-600 dark:text-gray-400 whitespace-nowrap">
|
||||
<span className="text-xs sm:text-sm text-gray-600 dark:text-gray-600 whitespace-nowrap">
|
||||
Freeze:
|
||||
</span>
|
||||
<select
|
||||
@@ -2354,7 +2354,7 @@ const TableEditor = () => {
|
||||
<thead className="bg-gray-50 dark:bg-gray-700 sticky top-[-1px] z-10">
|
||||
<tr>
|
||||
<th
|
||||
className={`px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 tracking-wider border-r border-gray-200 dark:border-gray-600 ${
|
||||
className={`px-4 py-3 text-left text-xs font-medium text-gray-600 dark:text-gray-300 tracking-wider border-r border-gray-200 dark:border-gray-600 ${
|
||||
frozenColumns > 0
|
||||
? "sticky left-0 z-20 bg-blue-50 dark:!bg-blue-900"
|
||||
: ""
|
||||
@@ -2390,7 +2390,7 @@ const TableEditor = () => {
|
||||
return (
|
||||
<th
|
||||
key={column.id}
|
||||
className={`relative px-4 py-3 text-left text-sm font-medium text-gray-500 dark:text-gray-300 tracking-wider hover:bg-gray-100 dark:hover:bg-gray-600 border-r border-gray-200 dark:border-gray-600 ${
|
||||
className={`relative px-4 py-3 text-left text-sm font-medium text-gray-600 dark:text-gray-300 tracking-wider hover:bg-gray-100 dark:hover:bg-gray-600 border-r border-gray-200 dark:border-gray-600 ${
|
||||
isFrozen
|
||||
? "sticky z-20 bg-blue-50 dark:!bg-blue-900"
|
||||
: ""
|
||||
@@ -2450,7 +2450,7 @@ const TableEditor = () => {
|
||||
className={`h-4 w-4 flex-shrink-0 ${
|
||||
sortConfig.key === column.id
|
||||
? "text-blue-600 dark:text-blue-400"
|
||||
: "text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
|
||||
: "text-gray-600 hover:text-gray-600 dark:hover:text-gray-300"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
@@ -2471,7 +2471,7 @@ const TableEditor = () => {
|
||||
<th className="px-4 py-3 text-center border-l-2 border-dashed border-gray-300 dark:border-gray-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 w-[60px]">
|
||||
<button
|
||||
onClick={addColumn}
|
||||
className="flex items-center justify-center text-gray-500 hover:text-blue-600 p-2 rounded-lg transition-colors group"
|
||||
className="flex items-center justify-center text-gray-600 hover:text-blue-600 p-2 rounded-lg transition-colors group"
|
||||
title="Add new column"
|
||||
>
|
||||
<Plus className="h-4 w-4 group-hover:scale-110 transition-transform" />
|
||||
@@ -2632,7 +2632,7 @@ const TableEditor = () => {
|
||||
>
|
||||
<span className="truncate block w-full">
|
||||
{cellValue || (
|
||||
<span className="text-gray-400 dark:text-gray-500 italic text-sm">
|
||||
<span className="text-gray-600 dark:text-gray-600 italic text-sm">
|
||||
Click to edit
|
||||
</span>
|
||||
)}
|
||||
@@ -2662,7 +2662,7 @@ const TableEditor = () => {
|
||||
>
|
||||
<button
|
||||
onClick={addRow}
|
||||
className="flex items-center justify-center gap-2 text-gray-500 hover:text-blue-600 px-3 py-2 rounded-lg transition-colors group whitespace-nowrap sticky left-4"
|
||||
className="flex items-center justify-center gap-2 text-gray-600 hover:text-blue-600 px-3 py-2 rounded-lg transition-colors group whitespace-nowrap sticky left-4"
|
||||
title="Add new row"
|
||||
>
|
||||
<Plus className="h-4 w-4 group-hover:scale-110 transition-transform" />
|
||||
@@ -2736,7 +2736,7 @@ const TableEditor = () => {
|
||||
Export Results
|
||||
{exportExpanded ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
|
||||
</h3>
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400">
|
||||
<div className="text-sm text-gray-600 dark:text-gray-600">
|
||||
{availableTables.length > 1 ? (
|
||||
<span>
|
||||
Database: {originalFileName || "Multi-table"} (
|
||||
@@ -2763,7 +2763,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-3 text-sm font-medium transition-colors whitespace-nowrap ${
|
||||
exportTab === "json"
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-b-2 border-blue-500"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<Braces className="h-4 w-4" />
|
||||
@@ -2774,7 +2774,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-3 text-sm font-medium transition-colors whitespace-nowrap ${
|
||||
exportTab === "csv"
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-b-2 border-blue-500"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<FileText className="h-4 w-4" />
|
||||
@@ -2785,7 +2785,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-3 text-sm font-medium transition-colors whitespace-nowrap ${
|
||||
exportTab === "tsv"
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-b-2 border-blue-500"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<FileText className="h-4 w-4" />
|
||||
@@ -2796,7 +2796,7 @@ const TableEditor = () => {
|
||||
className={`flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-3 text-sm font-medium transition-colors whitespace-nowrap ${
|
||||
exportTab === "sql"
|
||||
? "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border-b-2 border-blue-500"
|
||||
: "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
: "text-gray-600 dark:text-gray-600 hover:text-gray-900 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<Database className="h-4 w-4" />
|
||||
@@ -3318,7 +3318,7 @@ const ClearConfirmationModal = ({
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-gray-100 mb-2">
|
||||
This will permanently delete:
|
||||
</h4>
|
||||
<ul className="text-sm text-gray-600 dark:text-gray-400 space-y-1">
|
||||
<ul className="text-sm text-gray-600 dark:text-gray-600 space-y-1">
|
||||
{tableCount > 1 ? (
|
||||
<>
|
||||
<li>• {tableCount} tables</li>
|
||||
@@ -3632,7 +3632,7 @@ const ObjectEditorModal = ({ modal, onClose, onApply }) => {
|
||||
const renderVisualEditor = () => {
|
||||
if (!isValid) {
|
||||
return (
|
||||
<div className="h-full flex items-center justify-center text-gray-500 dark:text-gray-400 p-6">
|
||||
<div className="h-full flex items-center justify-center text-gray-600 dark:text-gray-600 p-6">
|
||||
<div className="text-center">
|
||||
<Code className="h-12 w-12 mx-auto mb-4 opacity-50" />
|
||||
<p>Invalid or unparseable data</p>
|
||||
@@ -3666,7 +3666,7 @@ const ObjectEditorModal = ({ modal, onClose, onApply }) => {
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
Object Editor
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-600">
|
||||
Row {modal.rowIndex} • Column: {modal.columnName} • Format:{" "}
|
||||
{modal.format.type.replace("_", " ")}
|
||||
</p>
|
||||
@@ -3681,7 +3681,7 @@ const ObjectEditorModal = ({ modal, onClose, onApply }) => {
|
||||
{isValid &&
|
||||
structuredData &&
|
||||
typeof structuredData === "object" && (
|
||||
<span className="text-gray-600 dark:text-gray-400">
|
||||
<span className="text-gray-600 dark:text-gray-600">
|
||||
{" • "}{Object.keys(structuredData).length} properties
|
||||
</span>
|
||||
)}
|
||||
@@ -3689,7 +3689,7 @@ const ObjectEditorModal = ({ modal, onClose, onApply }) => {
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 self-start"
|
||||
className="text-gray-600 hover:text-gray-600 dark:hover:text-gray-300 self-start"
|
||||
>
|
||||
<X className="h-6 w-6" />
|
||||
</button>
|
||||
@@ -3704,7 +3704,7 @@ const ObjectEditorModal = ({ modal, onClose, onApply }) => {
|
||||
className={`px-3 py-2 text-sm font-medium rounded-md transition-colors ${
|
||||
viewMode === "visual"
|
||||
? "bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300"
|
||||
: "text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
: "text-gray-600 hover:text-gray-900 dark:text-gray-600 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<Edit3 className="h-4 w-4 inline mr-2" />
|
||||
@@ -3715,7 +3715,7 @@ const ObjectEditorModal = ({ modal, onClose, onApply }) => {
|
||||
className={`px-3 py-2 text-sm font-medium rounded-md transition-colors ${
|
||||
viewMode === "raw"
|
||||
? "bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300"
|
||||
: "text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
: "text-gray-600 hover:text-gray-900 dark:text-gray-600 dark:hover:text-gray-200"
|
||||
}`}
|
||||
>
|
||||
<Code className="h-4 w-4 inline mr-2" />
|
||||
@@ -3845,7 +3845,7 @@ const InputChangeConfirmationModal = ({
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-gray-100 mb-2">
|
||||
This will permanently delete:
|
||||
</h4>
|
||||
<ul className="text-sm text-gray-600 dark:text-gray-400 space-y-1">
|
||||
<ul className="text-sm text-gray-600 dark:text-gray-600 space-y-1">
|
||||
{tableCount > 1 ? (
|
||||
<>
|
||||
<li>• {tableCount} imported tables</li>
|
||||
|
||||
Reference in New Issue
Block a user