Add Markdown support and update member features

The commit adds Markdown rendering capabilities and makes several UI/UX
improvements across member-related features including profile display,
peer support badges, and navigation structure.

Includes:
- Added @tailwindcss/typography plugin
- New Markdown rendering composable
- Simplified member navigation links
- Enhanced member profile layout and styling
- Added peer support badge component
- Improved mobile responsiveness
- Removed redundant icons and simplified UI
This commit is contained in:
Jennie Robinson Faber 2025-10-07 15:07:27 +01:00
parent fb02688166
commit 1f7a0f40c0
11 changed files with 375 additions and 432 deletions

View file

@ -429,28 +429,12 @@
<UFormField
label="Conversational Support Topics"
name="peerSupportSupportTopics"
description="Select emotional and conversational support areas"
>
<div class="space-y-2 mt-2">
<label
v-for="topic in availableSupportTopics"
:key="topic"
class="flex items-center gap-3 p-3 rounded-lg border border-ghost-700 hover:border-purple-500/50 transition-colors cursor-pointer"
:class="
formData.peerSupportSupportTopics.includes(topic)
? 'bg-purple-500/10 border-purple-500/50'
: 'bg-ghost-900/50'
"
>
<input
type="checkbox"
:value="topic"
v-model="formData.peerSupportSupportTopics"
class="rounded border-ghost-600 text-purple-500 focus:ring-purple-500 focus:ring-offset-0 bg-ghost-800"
/>
<span class="text-ghost-200">{{ topic }}</span>
</label>
</div>
<UCheckboxGroup
v-model="formData.peerSupportSupportTopics"
:items="availableSupportTopics"
color="primary"
/>
</UFormField>
<!-- Availability -->
@ -927,6 +911,9 @@ const hasChanges = computed(() => {
// Offering tag management
const addOfferingTag = () => {
const tag = currentOfferingTagInput.value.trim().replace(/,$/, "");
if (!Array.isArray(formData.offering.tags)) {
formData.offering.tags = [];
}
if (tag && !formData.offering.tags.includes(tag)) {
formData.offering.tags.push(tag);
currentOfferingTagInput.value = "";
@ -934,12 +921,16 @@ const addOfferingTag = () => {
};
const removeOfferingTag = (index) => {
if (!formData.offering.tags) return;
formData.offering.tags.splice(index, 1);
};
// Looking For tag management
const addLookingForTag = () => {
const tag = currentLookingForTagInput.value.trim().replace(/,$/, "");
if (!Array.isArray(formData.lookingFor.tags)) {
formData.lookingFor.tags = [];
}
if (tag && !formData.lookingFor.tags.includes(tag)) {
formData.lookingFor.tags.push(tag);
currentLookingForTagInput.value = "";
@ -947,6 +938,7 @@ const addLookingForTag = () => {
};
const removeLookingForTag = (index) => {
if (!formData.lookingFor.tags) return;
formData.lookingFor.tags.splice(index, 1);
};
@ -964,6 +956,9 @@ const removePeerSkillTopic = (index) => {
};
const addSuggestedSkillTopic = (tag) => {
if (!Array.isArray(formData.peerSupportSkillTopics)) {
formData.peerSupportSkillTopics = [];
}
if (!formData.peerSupportSkillTopics.includes(tag)) {
formData.peerSupportSkillTopics.push(tag);
}
@ -982,22 +977,32 @@ const loadProfile = () => {
// Load offering (handle both old string and new object format)
if (typeof memberData.value.offering === "string") {
formData.offering = { text: memberData.value.offering, tags: [] };
formData.offering.text = memberData.value.offering;
formData.offering.tags = [];
} else if (memberData.value.offering) {
formData.offering.text = memberData.value.offering?.text || "";
formData.offering.tags = Array.isArray(memberData.value.offering?.tags)
? [...memberData.value.offering.tags]
: [];
} else {
formData.offering = {
text: memberData.value.offering?.text || "",
tags: memberData.value.offering?.tags || [],
};
formData.offering.text = "";
formData.offering.tags = [];
}
// Load lookingFor (handle both old string and new object format)
if (typeof memberData.value.lookingFor === "string") {
formData.lookingFor = { text: memberData.value.lookingFor, tags: [] };
formData.lookingFor.text = memberData.value.lookingFor;
formData.lookingFor.tags = [];
} else if (memberData.value.lookingFor) {
formData.lookingFor.text = memberData.value.lookingFor?.text || "";
formData.lookingFor.tags = Array.isArray(
memberData.value.lookingFor?.tags,
)
? [...memberData.value.lookingFor.tags]
: [];
} else {
formData.lookingFor = {
text: memberData.value.lookingFor?.text || "",
tags: memberData.value.lookingFor?.tags || [],
};
formData.lookingFor.text = "";
formData.lookingFor.tags = [];
}
formData.showInDirectory = memberData.value.showInDirectory ?? true;
@ -1006,16 +1011,29 @@ const loadProfile = () => {
if (memberData.value.peerSupport) {
formData.peerSupportEnabled =
memberData.value.peerSupport.enabled || false;
formData.peerSupportSkillTopics =
memberData.value.peerSupport.skillTopics || [];
formData.peerSupportSupportTopics =
memberData.value.peerSupport.supportTopics || [];
formData.peerSupportSkillTopics = Array.isArray(
memberData.value.peerSupport.skillTopics,
)
? [...memberData.value.peerSupport.skillTopics]
: [];
formData.peerSupportSupportTopics = Array.isArray(
memberData.value.peerSupport.supportTopics,
)
? [...memberData.value.peerSupport.supportTopics]
: [];
formData.peerSupportAvailability =
memberData.value.peerSupport.availability || "";
formData.peerSupportMessage =
memberData.value.peerSupport.personalMessage || "";
formData.peerSupportSlackUsername =
memberData.value.peerSupport.slackUsername || "";
} else {
formData.peerSupportEnabled = false;
formData.peerSupportSkillTopics = [];
formData.peerSupportSupportTopics = [];
formData.peerSupportAvailability = "";
formData.peerSupportMessage = "";
formData.peerSupportSlackUsername = "";
}
// Load privacy settings (with defaults)