106 Commits
v0.1.1 ... main

Author SHA1 Message Date
cfa40d3825 feat: replace domain in sitemaps
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 56s
2025-09-25 22:38:36 -04:00
626f80a610 feat: Initial rank-math-seo integration
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m2s
2025-09-25 22:11:05 -04:00
4ebf092d66 minor: update TASLS 2025-09-25 21:37:00 -04:00
a8c52c91ee fix: prevent indexing virtual pages 2025-09-25 21:34:37 -04:00
e9c92840fc feat: Virtual page redirect, breadcrumb & menu items
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m5s
2025-09-25 21:28:23 -04:00
3f0d4dbb4e minor: update TASKS 2025-09-25 15:33:37 -04:00
e041408715 refactor: fieldGroupName => __typename
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 58s
2025-09-25 15:30:10 -04:00
ed479312fa feat: imageCenter field 2025-09-25 15:22:06 -04:00
8f893623ca chore: add theia thumbnails 2025-09-25 15:04:33 -04:00
4ac9ceb50e chore: ARCHITECTURE.md 2025-09-25 13:55:12 -04:00
dfa2cec646 minor: update tasks 2025-09-25 13:34:51 -04:00
cab4a8fe55 chore: update deps
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 58s
2025-09-25 11:35:49 -04:00
3119f29218 feat: template replacement
Some checks failed
Deploy WordPress and Nuxt / deploy (push) Has been cancelled
2025-09-25 11:33:02 -04:00
9f4d110d6e chore: update schema
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m5s
2025-09-25 11:01:21 -04:00
108fca0bcc fix: hierarchical location
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m0s
2025-09-25 10:58:26 -04:00
69d4c1f34a wip: abstract field groups 2025-09-25 10:53:28 -04:00
8fbac701f6 chore: updated planning / tasks
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m2s
2025-09-25 10:04:50 -04:00
b12f1fc2a2 chore: Update CLAUDE / PLANNING / TASKS 2025-09-25 09:30:16 -04:00
4c41ff2dae chore: update schema.graphql
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 56s
2025-09-24 16:23:47 -04:00
1817772c50 fix: breadcrumbs ancestors
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 56s
2025-09-24 16:20:32 -04:00
add3869f43 feat: listing_category
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 59s
2025-09-24 16:11:43 -04:00
425ee29ddc feat: group_post_listing 2025-09-24 16:04:33 -04:00
299213d5e9 refactor: membership => profile
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m6s
2025-09-24 16:01:46 -04:00
b631e4c06b feat: initial annonce cpt
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 55s
2025-09-24 15:53:19 -04:00
1f81cb4ad8 refactor: SectionWrapper
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 57s
2025-09-24 15:38:45 -04:00
5c49583287 refactor: nodes props
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 59s
2025-09-24 15:23:34 -04:00
5f2c464c9a refactor: shared useSection
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 59s
2025-09-24 15:16:20 -04:00
9af11d00cf wip: refactor sections 2025-09-24 15:14:48 -04:00
b2b9b2ba8f minor: change message
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 58s
2025-09-24 14:26:37 -04:00
204102e688 fix: useNodeByUri multiple errors
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 57s
2025-09-24 14:23:19 -04:00
7f01d44403 feat: better error handling in useNodeByUri
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 58s
2025-09-24 14:11:01 -04:00
5ce55b5c33 refactor: sections-map
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m6s
2025-09-24 14:05:47 -04:00
0bffe2768d wip: preview 2025-09-24 12:36:12 -04:00
cd4cf2e3e3 feat: backend preview logic 2025-09-24 12:02:36 -04:00
cd8c98be20 wip: reorganize helpers 2025-09-24 11:53:44 -04:00
68acbae012 wip: preview using GraphQL value 2025-09-24 11:50:06 -04:00
b8954be7eb wip: pass preview data 2025-09-24 10:55:49 -04:00
b11e1b3dc4 wip: Working preview request 2025-09-24 08:58:23 -04:00
67118cd6c0 wip: dynamic preview 2025-09-24 08:46:02 -04:00
d553d8021d fix: defineGraphqlServerOptions 2025-09-24 08:08:50 -04:00
ad9d266520 minor: builder edit in modal 2025-09-24 08:03:22 -04:00
0b46305977 chore: update deps
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m1s
2025-09-24 07:53:37 -04:00
23b4e13994 wip: Builder features 2025-09-22 14:22:21 -04:00
dcf12d9216 chore: update deps
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m1s
2025-09-22 13:51:24 -04:00
db4e81d852 minor: add some ids here and there 2025-09-22 12:00:04 -04:00
fe2b500684 feat: Initial TheSections 2025-09-22 11:49:48 -04:00
c6fce32c54 feat: Initial @nuxt/image setup 2025-09-22 11:10:31 -04:00
5e76f167e9 minor: eslint no-v-html off 2025-09-22 11:09:51 -04:00
a863da3e40 feat: isRedirecting auth
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m1s
2025-09-18 14:39:47 -04:00
056901e7e7 feat: redirect param to useAuthAction
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m3s
2025-09-18 14:14:57 -04:00
611237f73b minor: special pages breadcrumbs 2025-09-18 14:03:41 -04:00
6b078267de refactor: useAuth / useAuthActions
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m4s
2025-09-18 14:02:00 -04:00
5f23d4094e fix: logout form to 2025-09-18 13:57:08 -04:00
69f61f7ae2 feat: Initial middleware 2025-09-18 13:34:15 -04:00
834e640b31 feat: Initial SiteBreadcrumbs 2025-09-18 13:15:24 -04:00
2a70cf5533 minor: add The prefix 2025-09-18 13:10:39 -04:00
f49c76a642 minor: loggedIn => isLoggedIn
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m1s
2025-09-18 13:02:00 -04:00
c915d658d0 fix: hide label on mobile 2025-09-18 12:54:06 -04:00
1cea2fe9f8 refactor: Use AuthUser fragment for login / swithcTo
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m0s
2025-09-18 12:47:13 -04:00
48c8454f2a minor: rename onLoginSubmit / onLoginClick
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m2s
2025-09-18 12:28:29 -04:00
0e8dd8f01e fix: handleSwitchTo
Some checks failed
Deploy WordPress and Nuxt / deploy (push) Failing after 1m49s
2025-09-18 11:54:22 -04:00
4e9ad82d96 refactor: rename userSwitchTo
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m6s
2025-09-18 11:50:02 -04:00
3cc4b570d5 refactor: auth stuff 2025-09-18 11:39:29 -04:00
c82abe88e4 refactor: use onServerResponse for auth instead of server api 2025-09-18 10:23:09 -04:00
a661350e1c fix: useNodeByUri error handling
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m12s
2025-09-17 08:59:45 -04:00
7bcabc20db refactor: data fetching for page navigation
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m1s
2025-09-17 08:50:19 -04:00
346890c088 refactor: better project structure
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 6m3s
2025-09-17 08:41:42 -04:00
ba42386645 refactor: SiteHeaderTop*
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m2s
2025-09-16 15:00:41 -04:00
8f06c093a8 fix: front page breadcrumb 2025-09-16 14:55:54 -04:00
e3b0433626 minor: /auth => /connexion
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m0s
2025-09-16 14:06:17 -04:00
0e8b313608 wip: espace-membre page 2025-09-16 14:04:19 -04:00
e50918ac39 feat: option for breadcrumbs post types
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m7s
2025-09-16 13:54:24 -04:00
3d1e311fef refactor: breadcrumbs stuff 2025-09-16 13:51:03 -04:00
4cff390f41 fix: pass cookies with GraphQL request 2025-09-16 13:21:52 -04:00
50ea237667 wip: UserSwitchButton 2025-09-16 10:59:23 -04:00
88f8b6919a feat: launch.json 2025-09-16 10:38:08 -04:00
0fb82e59e0 minor: remove user-switching 2025-09-16 10:38:03 -04:00
cd2bfdfc0b feat: project permalink using ID 2025-09-16 10:01:42 -04:00
28186c9141 fix: Breadcrumbs
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 59s
2025-09-15 15:48:42 -04:00
ff5cc82384 fix: GraphQL breadcrumbs and address 2025-09-15 15:36:33 -04:00
4c3f0a26bf feat: Routes de l'arborescence
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 57s
2025-09-15 14:38:14 -04:00
0f00615f35 wip: field groups
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m9s
2025-09-15 14:29:55 -04:00
85b4c7f16b minor: membre public
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 57s
2025-09-15 12:58:45 -04:00
e05083a0ad minor: Emplacement => Lieu
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m0s
2025-09-15 12:54:16 -04:00
0fc62d25c3 feat: better user switching code
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m0s
2025-09-15 12:47:28 -04:00
98876f23b8 feat: Initial user switching mutations 2025-09-15 12:34:59 -04:00
c53fb152d4 minor: Claude instructions 2025-09-15 12:33:52 -04:00
9109dc748b chore: Initial Claude init
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m2s
2025-09-15 11:46:03 -04:00
29011e7dae chore: upate deps 2025-09-15 11:44:00 -04:00
f8b89da67a fix: refreshAuthToken
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m1s
2025-09-03 14:54:33 -04:00
7558da689d feat: Initial useNodeByUri
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 59s
2025-09-03 14:45:31 -04:00
b15beb961e chore: disable site indexing
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m1s
2025-09-03 13:59:42 -04:00
d947aa3c7b chore: update deps
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 59s
2025-09-03 13:20:50 -04:00
e8a6aa41cf minor: contributor should be public, not membership 2025-09-03 13:13:06 -04:00
3e15073ebb fix: headless home-url
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m2s
2025-08-27 14:42:38 -04:00
d77307fce0 feat: persistent PNPM_STORE_DIR
All checks were successful
Deploy WordPress and Nuxt / deploy (push) Successful in 1m1s
2025-08-27 14:19:06 -04:00
a1802e0991 chore: combine deploy scripts into one
Some checks failed
Deploy WordPress and Nuxt / deploy (push) Has been cancelled
2025-08-27 14:12:56 -04:00
a1b4c4f108 chore: update deps
All checks were successful
NuxtHub deployment / deploy (push) Successful in 59s
WordPress deployment / deploy (push) Successful in 8s
2025-08-27 14:02:44 -04:00
9d7f13d925 minor: remove unneeded steps 2025-08-27 14:01:41 -04:00
9b864d8828 fix: don't use nuxt-hub/action
All checks were successful
NuxtHub deployment / deploy (push) Successful in 1m31s
WordPress deployment / deploy (push) Successful in 8s
2025-08-27 13:54:04 -04:00
707dd510da fix: missing permissions
Some checks failed
NuxtHub deployment / deploy (push) Failing after 21s
WordPress deployment / deploy (push) Successful in 7s
2025-08-27 13:50:21 -04:00
850fd67db3 fix: deploy-nuxthub
Some checks failed
NuxtHub deployment / deploy (push) Failing after 22s
WordPress deployment / deploy (push) Successful in 8s
2025-08-27 13:49:02 -04:00
312a6f1b62 feat: Initial Nuxt app
Some checks failed
NuxtHub deployment / deploy (push) Failing after 21s
WordPress deployment / deploy (push) Successful in 8s
2025-08-27 13:37:40 -04:00
677d367226 fix: no need for pnpm/action-setup / actions/setup-node
Some checks failed
NuxtHub deployment / deploy (push) Failing after 2s
WordPress deployment / deploy (push) Successful in 9s
2025-08-27 13:35:20 -04:00
76e735d8e7 feat: deploy-nuxthub
Some checks failed
NuxtHub deployment / deploy (push) Failing after 28s
WordPress deployment / deploy (push) Successful in 8s
2025-08-27 13:33:44 -04:00
d8eb136038 minor: skip node building
All checks were successful
WordPress deployment / deploy (push) Successful in 9s
2025-08-27 13:26:46 -04:00
147 changed files with 52125 additions and 1405 deletions

343
.claude/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,343 @@
# ARCHITECTURE.md - CCAT Data Structure Reference
## Table of Contents
- [Custom Post Types Overview](#custom-post-types-overview)
- [Taxonomies Overview](#taxonomies-overview)
- [Custom Post Type Fields](#custom-post-type-fields)
- [Abstract Field Groups](#abstract-field-groups)
- [Field Relationships](#field-relationships)
- [Technical Implementation](#technical-implementation)
---
## Custom Post Types Overview
| CPT Name | Label | GraphQL Single | Rewrite Slug | Hierarchical | Description |
|----------|--------|----------------|--------------|--------------|-------------|
| `contributor` | Contributor | `Contributor` | -- | No | Artist/organization profiles |
| `event` | Event | `Event` | `evenement` | Yes | Base event descriptions without specific dates |
| `listing` | Listing | `Listing` | `offre` | No | Job offers and opportunities |
| `location` | Location | `Location` | `lieu` | Yes | Venue information with hierarchical structure |
| `page` | Page | `Page` | `page` | Yes | WordPress default pages with flexible content |
| `profile` | Profile | `Profile` | `profil` | No | User cultural profiles for members |
| `project` | Project | `Project` | `projet` | No | CCAT projects and initiatives |
| `representation` | Representation | `Representation` | -- | No | Specific event instances with dates/times/locations |
| `resource` | Resource | `Resource` | `ressource` | No | Document/link repository |
| `template` | Template | `Template` | -- | No | Reusable content blocks for flexible layouts |
---
## Taxonomies Overview
| Taxonomy Name | Label | Associated CPTs | Hierarchical | GraphQL Single | Description |
|---------------|--------|----------------|--------------|----------------|-------------|
| `discipline` | Discipline | `contributor`, `event` | Yes | `Discipline` | Artistic/cultural categories |
| `listing-category` | Listing Category | `listing` | Yes | `ListingCategory` | Job/proposal types |
| `project-category` | Project Category | `project` | Yes | `ProjectCategory` | CCAT project types |
| `resource-category` | Resource Category | `resource` | Yes | `ResourceCategory` | Resource organization categories |
---
## Custom Post Type Fields
### Contributor (`group_post_contributor`)
**Purpose:** Artist/organization profiles that can be linked to events
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `contributor_type` | Contributor type | select | Yes | Type of contributor (individual, organisation) |
| `alternative_titles` | Alternative titles | repeater | No | Alternative names for the contributor |
| `alternative_titles.name` | Name | text | Yes | Alternative name entry |
| `description` | Description | wysiwyg | No | Rich text description of contributor |
| `localities` | Localities | repeater | No | Physical locations associated with contributor |
| `localities.address` | Address | clone | Yes | Clones city address field for location |
| `disciplines` | Discipline(s) | taxonomy | No | Links to discipline taxonomy terms |
| `entity` | Entity | clone | No | External identifiers |
| `gallery` | Gallery | clone | No | Media gallery |
| `social` | Social | clone | No | Social media profiles |
### Event (`group_post_event`)
**Purpose:** Base event information without specific dates/times
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `event_type` | Event type | select | Yes | Type of event (Exposition, Festival, Spectacle) |
| `target_audience` | Target audience | select | Yes | Age group (Tout public, Enfants, Familial, Adultes 18+) |
| `description` | Description | wysiwyg | No | Rich text event description |
| `disciplines` | Discipline(s) | taxonomy | No | Links to discipline taxonomy terms |
| `is_wordless` | Wordless | true_false | No | Indicates if event is wordless |
| `languages` | Language(s) | acfe_languages | No | Event languages (conditional: shown if not wordless) |
| `entity` | Entity | clone | No | Clones abstract entity group (external identifiers) |
| `social` | Social | clone | No | Clones abstract social group (social media profiles) |
| `gallery` | Gallery | clone | No | Clones abstract gallery group (images/videos) |
| `credits` | Credits | clone | No | Clones abstract credits group (contributors and roles) |
### Listing (`group_post_listing`)
**Purpose:** Job offers and opportunities
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `listing_category` | Listing category | taxonomy | Yes | Links to listing_category taxonomy |
| `deadline` | Application deadline | date_picker | No | Application deadline date |
| `external_link` | External link | url | No | Link to external application |
### Location (`group_post_location`)
**Purpose:** Venue information for events
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `location_type` | Location type | select | Yes | Type of location (virtual, Bar, Salle de spectacle) |
| `description` | Description | wysiwyg | No | Rich text description of location |
| `address` | Address | clone | No | Clones geo address field (conditional: not shown for virtual) |
| `configurations` | Possible configurations | repeater | No | Different setup configurations for venue |
| `configurations.name` | Configuration name | text | Yes | Name of the configuration |
| `universal_access` | Universal access | checkbox | No | Accessibility features available |
| `entity` | Entity | clone | No | External identifiers |
| `social` | Social | clone | No | Social media profiles |
| `gallery` | Gallery | clone | No | Media gallery |
### Page (`group_post_page`)
**Purpose:** WordPress default pages with flexible content capabilities
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `builder` | Builder | clone | No | Clones abstract builder group (flexible content sections) |
**Note:** This field group extends WordPress's default `page` post type with flexible content capabilities. The default content editor is hidden (`hide_on_screen: the_content`) in favor of the flexible builder system.
### Profile (`group_post_profile`)
**Purpose:** User profile information for members
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `contact` | Contact | clone | Yes | Clones abstract contact group (personal info & address) |
| `billing_same` | Same as contact | true_false | No | Whether billing matches contact info |
| `billing` | Billing | clone | No | Separate billing contact info (conditional: shown if billing_same is false) |
| `profile_type` | Profile type | select | Yes | Type of profile (individual, collective, organization, institution) |
| `email_preferences` | Email preferences | group | No | Group containing email subscription preferences |
| `email_preferences.categories` | Categories | checkbox | No | Email categories to subscribe to |
| `email_preferences.disciplines` | Disciplines | checkbox | No | Discipline-based email preferences |
| `email_preferences.event_types` | Event types | checkbox | No | Event type email preferences |
| `email_preferences.mrc` | MRC | checkbox | No | Regional email preferences |
### Project (`group_post_project`)
**Purpose:** CCAT projects and initiatives
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `project_categories` | Project categories | taxonomy | Yes | Links to project_category taxonomy |
| `period` | Period | group | No | Project timeline |
| `period.start_month` | Start month | date_picker | Yes | Project start (month/year format) |
| `period.end_month` | End month | date_picker | No | Project end (month/year format) |
| `builder` | Builder | clone | No | Clones abstract builder group (flexible content sections) |
### Representation (`group_post_representation`)
**Purpose:** Specific event instances with dates/times
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `event` | Event | post_object | Yes | Links to base Event post |
| `description` | Description | wysiwyg | No | Specific description for this representation |
| `schedule_type` | Schedule type | select | Yes | Type of scheduling (range, days, multiple) |
| `range` | Range | group | No | Date range fields (conditional: when schedule_type = range) |
| `range.start_date` | Start date | date_picker | Yes | Range start date |
| `range.end_date` | End date | date_picker | Yes | Range end date |
| `days` | Days | repeater | No | Individual days (conditional: when schedule_type = days/multiple) |
| `days.start_date_time` | Start date/time | date_time_picker | Yes | Event start with time |
| `days.end_time` | End time | time_picker | No | Event end time |
| `offer` | Offer | clone | No | Clones abstract offer group (pricing, location, registration) |
### Resource (`group_post_resource`)
**Purpose:** Document repository
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `resource_category` | Resource category | taxonomy | Yes | Links to resource_category taxonomy |
| `documents` | Documents | repeater | No | List of documents |
| `documents.title` | Title | text | Yes | Document title |
| `documents.document_type` | Document type | select | Yes | Type of document (file, url) |
| `documents.file` | File | file | Yes | File upload (conditional: when document_type = file) |
| `documents.url` | URL | url | Yes | External URL (conditional: when document_type = url) |
### Template (`group_post_template`)
**Purpose:** Reusable content templates
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `builder` | Builder | clone | No | Clones abstract builder group (flexible content sections) |
---
## Abstract Field Groups
### Address City (`group_abstract_address_city`)
**Purpose:** City-level address information
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `address` | Address | acfe_address | Yes | Address with city-level search, Canada only |
### Address Contact (`group_abstract_address_contact`)
**Purpose:** Full contact address information
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `address` | Address | acfe_address | Yes | Complete address with street details, Canada only |
### Address Geo (`group_abstract_address_geo`)
**Purpose:** Geographic address with coordinates
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `address` | Address | acfe_address | Yes | Address with establishment search and lat/lng coordinates |
### Builder (`group_abstract_builder`)
**Purpose:** Flexible content builder with layout sections
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `sections` | Sections | flexible_content | No | Flexible content with layouts: |
| `sections.text_block` | Text block | layout | - | WYSIWYG content block |
| `sections.text_block.content` | Content | wysiwyg | Yes | Rich text content |
| `sections.template` | Template | layout | - | Reference to template post |
| `sections.template.template` | Template | post_object | Yes | Links to Template post type |
### Contact (`group_abstract_contact`)
**Purpose:** Personal contact information
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `first_name` | First name | text | Yes | Contact's first name |
| `last_name` | Last name | text | Yes | Contact's last name |
| `email` | Email | email | Yes | Contact email address |
| `phone` | Phone | acfe_phone_number | Yes | Phone number (Canada format) |
| `address` | Address | clone | Yes | Clones contact address field |
### Credits (`group_abstract_credits`)
**Purpose:** Attribution and contributor roles
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `contributions` | Contributions | repeater | No | List of contributor roles |
| `contributions.contributionTypes` | Contribution types | checkbox | Yes | Types of contribution (Auteur, Compositeur, Interprète) |
| `contributions.contributor` | Contributor | post_object | Yes | Links to Contributor post |
### Entity (`group_abstract_entity`)
**Purpose:** External entity identifiers
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `identifiers` | Identifiers | repeater | No | External identifier URLs |
| `identifiers.uri` | URI | url | Yes | External identifier URL |
### Gallery (`group_abstract_gallery`)
**Purpose:** Media gallery with images and videos
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `medias` | Medias | repeater | No | List of media items |
| `medias.mediaType` | Media type | select | Yes | Type of media (image, youtube) |
| `medias.image` | Image | image | Yes | Image upload (conditional: when mediaType = image) |
| `medias.youtube_url` | YouTube URL | url | Yes | YouTube video URL (conditional: when mediaType = youtube) |
### Offer (`group_abstract_offer`)
**Purpose:** Event offering details (pricing, registration, location)
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `attendance_mode` | Attendance mode | select | Yes | How event is attended (offline, online, mixed) |
| `is_async` | Is asynchronous | true_false | No | Whether online event is asynchronous |
| `offer_status` | Offer status | select | Yes | Event status (upcoming, confirmed, complete, cancelled, postponed) |
| `where` | Where | group | No | Location details (conditional: for offline/mixed events) |
| `where.location` | Location | post_object | Yes | Links to Location post |
| `where.configuration` | Configuration | select | No | Venue configuration |
| `pricing` | Pricing | group | No | Price information |
| `pricing.is_free` | Free | true_false | No | Whether event is free |
| `pricing.min_price` | Minimum price | number | Yes | Minimum price (conditional: if not free) |
| `registration` | Registration | group | No | Registration details |
| `registration.form` | Form | select | No | Registration form |
| `registration.url` | URL | url | No | Registration URL |
| `registration.email` | Email | email | No | Registration email |
| `registration.phone` | Phone | acfe_phone_number | No | Registration phone |
| `notifications` | Notifications | repeater | No | Scheduled notifications |
| `notifications.date_time` | Date/time | date_time_picker | Yes | When to send notification |
| `notifications.subject` | Subject | text | Yes | Email subject |
| `notifications.message` | Message | wysiwyg | Yes | Email message content |
| `notifications.sent_status` | Sent status | select | Yes | Notification status (planned, sent, failed) |
### Social (`group_abstract_social`)
**Purpose:** Social media profiles
| Field Name | Label | Type | Required | Description |
|------------|-------|------|----------|-------------|
| `profiles` | Profiles | repeater | No | List of social media profiles |
| `profiles.url` | URL | url | Yes | Social media profile URL |
---
## Field Relationships
### Post Object Relationships
- **Event → Representation**: Base events are instantiated through representations
- **Representation → Event**: Each representation references one base event
- **Representation → Location**: Event instances specify venue through offer.where.location
- **Contributor → Credits**: Contributors are linked to events through credits system
- **Template → Builder**: Templates contain flexible content sections that can be referenced
### Taxonomy Relationships
- **Discipline**: Applied to both `event` and `contributor` CPTs
- **Resource Category**: Applied to `resource` CPTs only
- **Project Category**: Applied to `project` CPTs only
- **Listing Category**: Applied to `listing` CPTs only
### Clone Field Usage
| Abstract Group | Used By CPTs |
|----------------|--------------|
| Address City | Contributor (locality) |
| Address Contact | Profile (contact, billing) |
| Address Geo | Location (address) |
| Builder | Project, Template, Page |
| Contact | Profile (contact, billing) |
| Credits | Event |
| Entity | Event, Contributor, Location |
| Gallery | Event, Contributor, Location |
| Offer | Representation |
| Social | Event, Contributor, Location, Options Page |
---
## Technical Implementation
### GraphQL Integration
- All CPTs enabled for GraphQL with custom single/plural names
- All fields set `show_in_graphql: 1` for API exposure
- Required fields use `graphql_non_null: 1` for schema validation
- Custom GraphQL field names follow camelCase convention
### ACF Extended Pro Features
- **Advanced Address Fields**: Google Places integration, Canada-specific
- **Phone Number Fields**: Country-specific formatting (Canada)
- **Language Selection**: Multi-language support with conditional logic
- **Flexible Content**: Modal editing, preview capabilities
- **Template System**: Reusable content blocks with clone functionality
### Conditional Logic Patterns
- Address fields hidden for virtual locations (`location_type != 'virtual'`)
- Language fields hidden for wordless events (`is_wordless != 1`)
- Billing fields conditional on "same as contact" toggle
- Pricing fields conditional on free/paid status
- Schedule layouts vary based on schedule type selection
### WordPress Integration
- Custom rewrite slugs in French for public-facing URLs
- Hierarchical structure for events and locations
- Thumbnail and excerpt support for content display
- Page attributes for ordering and parent-child relationships
- Translation-ready with `__()` functions and 'ccat' text domain
### Performance Considerations
- Clone fields reduce field duplication and maintain consistency
- Taxonomy relationships indexed for efficient querying
- GraphQL schema optimized with proper field exposure
- Conditional field loading reduces unnecessary data transfer

399
.claude/CLAUDE.md Normal file
View File

@@ -0,0 +1,399 @@
# CLAUDE.md - CCAT Project Guide
## 🚨 CRITICAL WORKFLOW REQUIREMENTS
### Before Starting ANY Work Session:
1. **ALWAYS read `.claude/PLANNING.md`** - Contains current project status, decisions, and context
2. **Check `.claude/TASKS.md`** - Review all pending tasks and their priorities
3. **Mark completed tasks immediately** - Update task status as you complete work
4. **Add newly discovered tasks** - Document any new tasks you identify during work
### Task Management Protocol:
- Update `.claude/TASKS.md` with progress and completion status
- Add context and notes for future sessions
- Prioritize tasks based on current project phase
- Document dependencies and blockers
---
## Project Overview
**CCAT Website** - Digital platform for Conseil de la culture de l'Abitibi-Témiscamingue
A comprehensive cultural community platform using WordPress as both backend CMS and theme container, with Nuxt 4 integrated as a custom theme providing the frontend experience.
### Key Objectives
- Centralize cultural information and events for the Abitibi-Témiscamingue region
- Provide platform for artists and cultural organizations
- Enable event management and subscription capabilities
- Foster community engagement through membership features
- Streamline administrative tasks for CCAT staff
---
## Architecture Overview
### WordPress Theme Integration
- **Nuxt-in-WordPress**: Nuxt 4 runs within WordPress theme context
- **Hybrid Rendering**: PHP handles WordPress logic, Nuxt handles frontend
- **Composer Dependencies**: Plugin management via WPackagist / private repository
- **ACF Integration**: Deep integration with ACF + ACF Extended Pro
- **Content Preview**: SSR-based preview system via iframe
### Tech Stack
#### WordPress Theme Structure
- **WordPress**: CMS + Custom theme containing Nuxt 4
- **Plugins**: Managed via Composer + WPackagist
- **Theme Structure**: Combines PHP logic with Nuxt 4 frontend
- **Directory Layout**: `app/` `server/` `shared/` (Nuxt) + `acf-json/` `includes/` (WordPress)
#### Frontend (Nuxt 4 in WordPress Theme)
- **Framework**: Nuxt 4 (embedded in WordPress theme)
- **UI**: Nuxt UI components + custom UI components
- **GraphQL**: Nuxt GraphQL middleware (client)
- **Auth**: JWT authentication for WPGraphQL
- **Deployment**: Gitea Actions (push-to-deploy)
- **Images**: @nuxt/image optimization
- **Maps**: Leaflet for interactive maps
#### Backend & Integrations
- **CMS**: WordPress with WPGraphQL + JWT Authentication
- **Custom Fields**: Advanced Custom Fields (ACF) + ACF Extended Pro
- **Content**: ACF Flexible Fields for dynamic layouts
- **Email**: Mailchimp (likely PHP integration)
- **Payments**: Stripe (likely PHP integration)
- **Import**: AirTable (non-destructive)
- **Preview**: ACF Extended Pro content preview via iframe/SSR
---
## Content Structure
### Custom Post Types (CPT)
```
Contributor - Artist / organization profiles
Event - Base event descriptions
Listing - Job offers/proposals (with deadlines)
Location - Venue information
Profile - User cultural profiles
Project - CCAT projects
Representation - Event instances (when/where)
Resource - Document/link repository
Template - Reusable ACF content blocks
```
### Taxonomies
```
Discipline - Artistic/cultural categories
Listing Category - Job/proposal types
Project Category - CCAT project types
Resource Category - Resource organization
Post Category - Standard WordPress
```
### User System
- **Authentication**: JWT tokens via WPGraphQL
- **Free Membership**: Basic profile + content management
- **Premium Membership**: Enhanced features (likely PHP Stripe integration)
- **Admin Roles**: Full content + user management + impersonation
- **Member Zones**: Protected areas for account and profiles management
### Event System
- **Event CPT**: Base event info (no dates)
- **Representation CPT**: Specific event instances (date/location)
- **Location CPT**: Venue information (hierarchical as Venue / Room)
- **Contributor CPT**: People involved with the event (performers, organizers, etc)
- **Subscriptions**: Free/paid registration with bulk options
- **Calendar**: Interactive display with filtering
---
## Code Organization
### WordPress Theme Directory Structure
```
wp-content/themes/ccat/
├── acf-json/ # ACF field group definitions
├── app/ # Nuxt 4 app directory
│ ├── assets/
│ │ ├── css/ # Styles
│ │ └── svg/ # Custom icons and vector images
│ ├── components/
│ │ ├── auth/ # Authentication components
│ │ ├── nodes/ # Main page components per CPT
│ │ ├── sections/ # Flexible content layouts
│ │ ├── site/ # Header, footer, navigation
│ │ └── ui/ # Custom UI components
│ ├── composables/
│ │ ├── useAuth.js # JWT authentication & tokens
│ │ ├── useMemberArea.js # Member zone functionality
│ │ ├── useMemberSignup.js # Registration flows
│ │ ├── useNodeByUri.js # Content fetching by URI
│ │ ├── useResponsive.js # Responsive utilities
│ │ └── useSiteOptions.js # ACF options page data
│ ├── graphql/ # GraphQL operations (*.gql)
│ ├── layouts/ # Nuxt layouts
│ ├── middleware/ # Nuxt middlewares
│ ├── pages/ # Nuxt pages
│ └── plugins/
├── includes/ # PHP functions and classes
│ ├── core/ # Core theme features
│ ├── cpt/ # Custom post types
│ ├── graphql/ # Custom WPGraphQL types, queries and mutations
│ ├── taxonomies/ # Custom taxonomies
│ └── vendors/ # 3rd party integrations
├── languages/ # WordPress theme translations
├── layouts/ # ACF Extended PRO templates (for content preview)
├── public/ # Nuxt 4 public directory
├── server/ # Nuxt 4 server directory
│ ├── api/ # API endpoints
│ ├── graphql/ # Server side GraphQL operations
│ └── utils/ # Auto-imported server utils
├── shared/ # Shared utilities/types
│ ├── types/ # Shared types
│ └── utils/ # Auto-imported shared utils
├── functions.php # WordPress theme functions
└── style.css # WordPress theme header
```
### Component Architecture
- **Nodes**: Main page components mapped to CPT types
- **Sections**: Flexible content layout components for ACF fields
- **Auth**: Authentication flows and protected content
- **Site**: Global site components (header, footer, nav)
- **UI**: Reusable custom UI components
---
## Development Guidelines
### WordPress Theme Development
- **Theme Structure**: Follow Nuxt 4 directory conventions within WordPress theme
- **PHP Integration**: Handle WordPress-specific logic, authentication, integrations
- **Composer**: Manage plugins via composer.json and WPackagist
- **ACF Configuration**: Store field groups in acf-json/ for version control
- **Custom Functions**: Organize PHP logic in includes/ directory
### Nuxt 4 (Within WordPress Theme)
- Use Nuxt UI components + custom UI components
- Implement SSR for SEO optimization and content preview
- Use Nuxt GraphQL middleware for all API calls
- JWT token management and refresh handling
- Mobile-first responsive design
- Leverage @nuxt/image for all media
- Follow accessibility standards (WCAG 2.1 AA)
---
## Key Features Implementation
### Member Management
- JWT-based registration/login with email verification
- Token refresh and session management
- Profile creation/editing (linked to Profile CPT)
- Premium membership upgrades (likely via PHP/Stripe)
- Content creation permissions based on membership
- Admin impersonation for user support
### Event Management
- Calendar view with Leaflet map integration
- Event subscription forms (free/paid via Stripe)
- Bulk attendee registration for admins
- Email confirmations via Mailchimp
- Admin tools for subscription management
### Content Management & Preview
- ACF Flexible Fields for dynamic content sections
- Template CPT for reusable content blocks
- ACF Extended Pro preview system (iframe + SSR)
- Image uploads with point-of-interest cropping
- Automated URL redirects on slug changes
- Virtual pages (redirect to first child)
- Real-time content preview during editing
### Admin Tools
- User management and moderation
- User impersonation for support purposes
- Event approval workflows
- Subscription monitoring
- Content import from AirTable
- Event webscraping configuration
### Integrations (Likely PHP-based)
- **Mailchimp**: User sync, newsletters, transactional emails (PHP API)
- **Stripe**: Payment processing, subscription billing (PHP SDK)
- **AirTable**: Import existing content non-destructively
- **Webscraping**: Automated event discovery from external sources
---
## Development Patterns & Solutions
### WordPress Theme Integration
- Use WordPress hooks and filters for theme integration
- Leverage ACF Extended Pro for enhanced field management
- Implement content preview via SSR iframe system
- Handle both PHP logic and Nuxt rendering in single theme
### GraphQL & Authentication
- Use Nuxt GraphQL middleware for all API calls
- Implement JWT token storage and refresh logic
- Handle authentication state across SSR/client
- Implement proper error handling for expired tokens
- Admin impersonation with separate token management
### Content Preview System
- ACF Extended Pro iframe preview integration
- SSR rendering for preview content via Nuxt server
- Real-time preview updates during content editing
- Flexible content section rendering in isolation
### State Management
- Use Nuxt's built-in state management
- Implement JWT token persistence and refresh
- Handle impersonation state for admins
- Site options management via useSiteOptions
### Form Handling & Payments (PHP Integration)
- Use Nuxt UI form components on frontend
- Handle form submissions via WordPress/PHP backend
- Mailchimp API integration in PHP for email management
- Stripe SDK integration in PHP for payment processing
- Webhook handling for payment events in PHP
---
## Implementation Timeline
### Phase 1: Foundation
1. WordPress theme setup with Nuxt 4 integration
2. Composer configuration for plugin management
3. WPGraphQL + JWT Authentication setup
4. Core CPT structure with ACF field groups
5. Basic Nuxt components (auth, nodes, sections)
6. ACF Extended Pro preview system
### Phase 2: Core Features
1. Member registration/profile management (useAuth, useMemberArea)
2. Event calendar with Leaflet maps
3. Flexible content sections with preview
4. Node-based page components per CPT
5. Site-wide components (header, footer, navigation)
6. Mailchimp integration (PHP)
### Phase 3: Advanced Features
1. Stripe payment integration (PHP)
2. Event subscription system
3. Premium membership features
4. Admin impersonation functionality
5. Advanced admin tools
6. AirTable import system
### Phase 4: Enhancement & Launch
1. Webscraping tool implementation
2. Performance optimization
3. Advanced search/filtering
4. Analytics integration
5. Final testing and launch preparation
---
## Technical Requirements
### Performance Considerations
- Optimize GraphQL queries (avoid N+1)
- Implement proper caching strategies
- Use @nuxt/image for all media optimization
- WordPress theme performance optimization
- ACF Extended Pro preview performance
- PHP integration efficiency (Mailchimp, Stripe)
- Monitor Core Web Vitals
### Security Requirements
- Sanitize all GraphQL inputs
- WordPress security best practices
- Implement proper CORS policies
- Use JWT tokens for authentication
- Secure PHP integrations (Mailchimp, Stripe APIs)
- Validate payment webhooks in PHP
- ACF Extended Pro security considerations
- Regular security updates for WordPress and plugins
### Testing Strategy
- Unit tests for utilities and composables
- Integration tests for GraphQL operations
- WordPress/PHP integration testing
- E2E tests for critical user flows
- Payment testing with Stripe test mode (PHP)
- Email testing with Mailchimp sandbox (PHP)
- Content preview functionality testing
---
## Deployment & Environment
### Deployment Notes
- WordPress theme with integrated Nuxt 4 frontend
- Plugin management via Composer + WPackagist
- CI/CD: Push-to-deploy via Gitea Actions
- Database: Optimized for GraphQL queries
- Assets: @nuxt/image handles optimization
- ACF field groups versioned in acf-json/
- SSL/TLS required for all environments
- JWT tokens for secure API communication
### Environment Variables
```
# WordPress/Nuxt Integration
NUXT_GRAPHQL_ENDPOINT= # WordPress GraphQL endpoint
NUXT_SESSION_PASSWORD= # JWT authentication secret
NUXT_HUB_PROJECT_KEY= # NuxtHub project reference
# Third-party Services (likely PHP env vars)
MAILCHIMP_API_KEY= # Mailchimp integration
STRIPE_SECRET_KEY= # Stripe payments
STRIPE_PUBLISHABLE_KEY= # Stripe public key
AIRTABLE_API_KEY= # AirTable import key
```
### Useful Commands
```bash
# Development
npm run dev # Start Nuxt dev server (within WordPress theme)
npm run build:typecheck # Check for TypeScript errors
npm run build # Build for production
composer install # Install WordPress plugins
git push origin main # Deploy via Gitea Actions
# WordPress
composer update # Update plugin dependencies
```
---
## Resources & Documentation
### Core Technologies
- [Nuxt 4 Documentation](https://nuxt.com/)
- [Nuxt GraphQL Middleware](https://nuxt.com/modules/graphql-middleware)
- [WordPress Theme Development](https://developer.wordpress.org/themes/)
- [WPGraphQL Docs](https://www.wpgraphql.com/)
- [WPGraphQL JWT Authentication](https://github.com/wp-graphql/wp-graphql-jwt-authentication)
### Content & Fields
- [ACF Documentation](https://www.advancedcustomfields.com/)
- [ACF Extended Pro](https://www.acf-extended.com/)
- [Composer + WPackagist](https://wpackagist.org/)
### Integrations
- [Stripe PHP SDK](https://github.com/stripe/stripe-php)
- [Mailchimp API PHP](https://mailchimp.com/developer/marketing/docs/fundamentals/)
- [Leaflet Documentation](https://leafletjs.com/)
### Deployment
- [Gitea Actions](https://docs.gitea.io/en-us/usage/actions/)
---
**Remember:** This is a WordPress theme containing Nuxt 4, not a separate frontend. The integration between WordPress/PHP and Nuxt is key to the architecture. Prioritize user experience, accessibility, and community engagement in all development decisions.

407
.claude/PLANNING.md Normal file
View File

@@ -0,0 +1,407 @@
# PLANNING.md - CCAT Project Planning Document
## 🎯 Project Vision
### Mission Statement
Create a comprehensive digital platform that serves as the central hub for the cultural community of Abitibi-Témiscamingue, connecting artists, organizations, and cultural enthusiasts while promoting regional cultural activities and fostering community engagement.
### Core Values
- **Community First**: Every feature should strengthen connections within the cultural community
- **Accessibility**: Platform must be accessible to all users regardless of technical expertise
- **Cultural Promotion**: Showcase and celebrate the rich cultural diversity of the region
- **User Empowerment**: Enable artists and organizations to manage their own content
- **Transparency**: Open and clear communication about events, opportunities, and resources
### Success Metrics
- **Community Growth**: Increase in registered cultural profiles and active members
- **Event Engagement**: Higher attendance and participation in cultural events
- **Content Creation**: Volume and quality of user-generated cultural content
- **Regional Impact**: Measurable increase in cultural activity awareness and participation
- **User Satisfaction**: Positive feedback and continued platform usage
---
## 🏗️ Architecture Overview
### System Architecture Philosophy
**Hybrid WordPress-Nuxt Integration**: A WordPress theme that embeds Nuxt 4, combining the content management power of WordPress with the modern frontend capabilities of Nuxt.
### Architecture Principles
- **Content-First Design**: WordPress CMS handles all content management
- **Modern Frontend Experience**: Nuxt 4 provides fast, interactive user interface
- **API-Driven**: GraphQL API layer separates content from presentation
- **Progressive Enhancement**: Core functionality works without JavaScript
- **Mobile-First**: Responsive design prioritizing mobile experience
- **Performance Optimized**: Fast loading times and efficient resource usage
### Data Flow Architecture
```
User Request → WordPress (PHP) → WPGraphQL → Nuxt Frontend → User Interface
↓ ↑
WordPress Admin ← ACF Fields ← Content Management ← User Actions
Third-party Integrations (Mailchimp, Stripe, AirTable)
```
### Content Architecture
- **Hierarchical Structure**: Organized content types with clear relationships
- **Flexible Content**: ACF flexible fields for dynamic page layouts
- **Reusable Components**: Template CPT for consistent content blocks
- **User-Generated Content**: Community members can create and manage profiles
- **Administrative Control**: Staff can moderate and approve content
---
## 💻 Technology Stack (Current Implementation)
### Core Platform - ✅ IMPLEMENTED
| Component | Technology | Version | Purpose | Status |
|-----------|------------|---------|---------|---------|
| **CMS** | WordPress | Latest | Content management system | ✅ Configured |
| **Frontend** | Nuxt | 4.1.2 | Modern Vue.js framework | ✅ Integrated |
| **UI Framework** | Nuxt UI | 4.0.0 | Component library | ✅ Configured |
| **Database** | MySQL | 8.0+ | Data storage | ✅ Operational |
| **Language** | PHP | 8.1+ | WordPress backend | ✅ Compatible |
| **Language** | TypeScript | 5.9.2 | Frontend development | ✅ Configured |
### WordPress Plugins & Extensions
| Plugin | Purpose | License |
|--------|---------|---------|
| **WPGraphQL** | GraphQL API layer | Free |
| **WPGraphQL JWT Authentication** | API authentication | Free |
| **Advanced Custom Fields Pro** | Custom field management | Commercial |
| **ACF Extended Pro** | Enhanced ACF features + preview | Commercial |
### Frontend Technologies
| Technology | Purpose | Integration |
|------------|---------|-------------|
| **Vue 3** | Component framework | Via Nuxt 4 |
| **Nuxt UI** | UI component library | Primary UI framework |
| **@nuxt/image** | Image optimization | Asset handling |
| **Nuxt GraphQL Middleware** | GraphQL client | API communication |
| **Leaflet** | Interactive maps | Event locations |
### Third-Party Integrations
| Service | Purpose | Implementation |
|---------|---------|----------------|
| **Mailchimp** | Email marketing & transactional emails | PHP SDK |
| **Stripe** | Payment processing | PHP SDK |
| **AirTable** | Data import system | API integration |
### Development Tools
| Tool | Purpose | Usage |
|------|---------|-------|
| **Composer** | PHP dependency management | Plugin management via WPackagist |
| **npm/pnpm** | Node.js package management | Frontend dependencies |
| **Gitea Actions** | CI/CD pipeline | Automated deployment |
| **TypeScript** | Type safety | Frontend development |
---
## 🛠️ Required Tools & Environment
### Development Environment Requirements
#### Local Development Setup
- **PHP**: Version 8.1 or higher
- **Node.js**: Version 18 or higher
- **MySQL**: Version 8.0 or higher
- **Composer**: Latest version for PHP dependencies
- **npm/pnpm**: For JavaScript package management
#### WordPress Development Tools
- **WordPress**: Latest version
- **WP-CLI**: WordPress command line interface
- **Local development environment**: (LocalWP, XAMPP, Docker, or similar)
#### Frontend Development Tools
- **Code Editor**: VS Code recommended with extensions:
- Vue Language Features (Volar)
- TypeScript Vue Plugin (Volar)
- GraphQL extension
- PHP extension
- **Browser Developer Tools**: Chrome/Firefox DevTools
- **GraphQL Playground**: For API testing
### Production Environment Requirements
#### Hosting Requirements
- **PHP**: 8.1+ with required extensions
- **MySQL/MariaDB**: 8.0+ or 10.6+
- **Web Server**: Apache 2.4+ or Nginx 1.20+
- **SSL Certificate**: Required for secure authentication
- **Memory**: Minimum 512MB PHP memory limit
- **Storage**: SSD recommended for performance
#### Performance Requirements
- **CDN**: Not required initially (@nuxt/image handles optimization)
- **Caching**: WordPress object caching recommended
- **Backup System**: Automated daily backups
- **Monitoring**: Server and application monitoring
### Development Workflow Tools - 🚧 PARTIALLY CONFIGURED
#### Version Control - ✅ OPERATIONAL
- **Git**: Version control system (configured)
- **Gitea**: Self-hosted Git service with Actions (.gitea/workflows configured)
- **Git Flow**: Branching strategy for organized development (main branch active)
#### Project Management - ✅ CONFIGURED
- **TASKS.md**: Task tracking using markdown checkboxes (comprehensive)
- **PLANNING.md**: This document for project planning (updated)
- **CLAUDE.md**: Development guide for AI assistance (detailed)
#### Testing Tools - ⏳ NOT IMPLEMENTED
- **Vitest**: Unit testing for frontend (not configured)
- **PHPUnit**: Unit testing for WordPress/PHP (not configured)
- **Playwright**: End-to-end testing (not configured)
- **GraphQL testing tools**: For API validation (not configured)
---
## ⚙️ Configuration & Deployment
### Environment Variables
```bash
# WordPress/Nuxt Integration - ✅ CONFIGURED
NUXT_GRAPHQL_ENDPOINT="https://wp.cultureat.ca/graphql" # WordPress GraphQL endpoint
NUXT_SESSION_PASSWORD= # JWT authentication secret (configured)
NUXT_HUB_PROJECT_KEY= # NuxtHub project reference (configured)
# Third-party Services - ⏳ PENDING IMPLEMENTATION
MAILCHIMP_API_KEY= # Mailchimp integration (not implemented)
STRIPE_SECRET_KEY= # Stripe payments (not implemented)
STRIPE_PUBLISHABLE_KEY= # Stripe public key (not implemented)
AIRTABLE_API_KEY= # AirTable import key (not implemented)
```
### Useful Commands (Current Implementation)
```bash
# Development - ✅ WORKING
pnpm dev:nuxt # Start Nuxt dev server --host (configured)
pnpm build:typecheck # Check for TypeScript errors (working)
pnpm build:nuxt # Build Nuxt for production (working)
pnpm lint # ESLint with --fix (working)
composer install # Install WordPress plugins (working)
git push origin main # Deploy via Gitea Actions (configured)
# WordPress - ✅ WORKING
composer update # Update plugin dependencies (working)
wp-cli commands # WordPress CLI available
# Additional Available Commands
pnpm deploy # NuxtHub deployment
pnpm preview # NuxtHub preview
pnpm postinstall:nuxt # Nuxt preparation
```
### Deployment Configuration - ✅ CONFIGURED
- **CI/CD**: Gitea Actions configured for push-to-deploy
- **Hosting**: NuxtHub integration with Cloudflare Workers
- **Domain**: cultureat.ca configured in nuxt.config.ts
- **SSL**: Required and configured for secure authentication
- **Build System**: Optimized for production with Nitro preset
### Implementation Specifics
#### File Structure Analysis - ✅ IMPLEMENTED
```
wp-content/themes/ccat/
├── acf-json/ # 25+ ACF field groups (212KB total)
├── app/ # Nuxt 4 application
│ ├── components/ # 7 directories, organized by function
│ ├── composables/ # 7 composables (3 stubs need completion)
│ ├── graphql/ # 5 GraphQL operations
│ └── pages/ # 4 pages (member-focused + dynamic routing)
├── includes/ # WordPress PHP logic
│ ├── cpt/ # 9 Custom Post Types (all implemented)
│ ├── taxonomies/ # 4 Custom Taxonomies (all implemented)
│ └── graphql/ # Custom GraphQL extensions
├── server/ # Nuxt server directory
│ └── schema.graphql # 866KB generated schema
└── package.json # 18 dependencies, 4 dev dependencies
```
#### Critical Technical Debt Identified
1. **Member Composables**: `useMemberSignup.ts` and `useMemberArea.ts` are 49-byte stubs
2. **Footer Implementation**: TheSiteFooter.vue shows "TODO" - needs top section content
3. **Site Navigation**: Header/navigation fully implemented with responsive design
4. **Integration Gaps**: No third-party service integrations (Mailchimp, Stripe, AirTable)
5. **Testing Coverage**: Zero test files found in entire project
---
## 📋 Development Phases & Milestones
### Phase 1: Foundation (Months 1-3)
**Goal**: Establish core architecture and basic functionality
- WordPress theme with Nuxt 4 integration
- Authentication system with JWT
- Content structure (CPTs, taxonomies, ACF fields)
- Basic GraphQL API functionality
### Phase 2: Core Features (Months 4-6)
**Goal**: Implement primary user-facing features
- Member registration and profile management
- Event system with calendar integration
- Content management with flexible layouts
- Site navigation and global components
### Phase 3: Advanced Features (Months 7-9)
**Goal**: Add premium features and integrations
- Payment processing (Stripe integration)
- Email marketing (Mailchimp integration)
- Event subscription system
- Admin tools and user impersonation
### Phase 4: Enhancement & Launch (Months 10-12)
**Goal**: Polish, optimize, and prepare for production
- Performance optimization
- Security audit and testing
- Content import from existing systems
- User training and documentation
---
## 🎨 User Experience Strategy
### Target User Groups
1. **Cultural Artists**: Individual artists showcasing work and finding opportunities
2. **Cultural Organizations**: Groups promoting events and managing memberships
3. **Community Members**: Residents interested in cultural activities
4. **CCAT Staff**: Administrators managing the platform and content
5. **Event Organizers**: People creating and promoting cultural events
### User Journey Design
- **Discovery**: Easy browsing of events and cultural profiles
- **Engagement**: Simple registration and profile creation
- **Participation**: Event subscription and community interaction
- **Contribution**: Content creation and profile management
- **Administration**: Streamlined content moderation and user management
### Accessibility Commitments
- **WCAG 2.1 AA Compliance**: Meet accessibility standards
- **Mobile-First Design**: Optimal experience on all devices
- **Performance**: Fast loading times even on slow connections
- **Multilingual Support**: Prepared for French/English localization
- **Inclusive Design**: Consider diverse user needs and abilities
---
## 🔐 Security & Privacy Considerations
### Data Protection
- **GDPR Compliance**: Handle personal data responsibly
- **User Consent**: Clear opt-ins for email and data collection
- **Data Minimization**: Collect only necessary information
- **Right to Deletion**: Allow users to delete their accounts
### Security Measures
- **Authentication**: JWT tokens with proper expiration
- **Authorization**: Role-based access control
- **Input Validation**: Sanitize all user inputs
- **API Security**: Rate limiting and proper error handling
- **Regular Updates**: Keep all plugins and core systems updated
### Privacy Features
- **Profile Visibility**: User control over profile information
- **Email Preferences**: Granular email subscription controls
- **Content Ownership**: Clear guidelines for user-generated content
- **Admin Transparency**: Clear communication about moderation policies
---
## 📊 Analytics & Success Measurement
### Key Performance Indicators (KPIs)
- **User Engagement**: Active users, session duration, page views
- **Content Creation**: Number of profiles, events, and user posts
- **Event Participation**: Event views, subscriptions, and attendance
- **Community Growth**: New registrations and profile completions
- **Technical Performance**: Page load times, uptime, error rates
### Analytics Implementation
- **Privacy-Focused**: Use privacy-respecting analytics tools
- **User Behavior**: Track user flows and feature usage
- **Performance Monitoring**: Real-time application performance
- **Content Analytics**: Most popular content and search terms
---
## 🚀 Launch Strategy
### Pre-Launch Preparation
- **Content Migration**: Import existing cultural data
- **User Training**: Staff and power user training sessions
- **Beta Testing**: Limited release to core community members
- **Documentation**: Complete user and admin guides
- **Marketing Materials**: Prepare launch communications
### Launch Phases
1. **Soft Launch**: Limited user base, gather feedback
2. **Community Launch**: Open to cultural organizations
3. **Public Launch**: Full public availability
4. **Post-Launch**: Monitor, support, and iterate
### Success Criteria for Launch
- **Technical Stability**: No critical bugs or performance issues
- **User Adoption**: Target number of registered profiles
- **Content Quality**: Sufficient content for engaging experience
- **User Satisfaction**: Positive feedback from beta users
- **Admin Readiness**: Staff comfortable with platform management
---
## 📊 Current Implementation Status
### Overall Project Progress: **~65% Complete**
### ✅ Completed Infrastructure
- **WordPress Theme Structure**: Complete Nuxt 4 integration within WordPress theme
- **Content Management**: 9 Custom Post Types, 4 Taxonomies, 25+ ACF field groups
- **GraphQL API**: Comprehensive 866KB schema with all content types exposed
- **Authentication**: JWT-based system with role management and impersonation
- **Core Components**: Node components for major content types, basic sections system
- **Development Environment**: Full toolchain with TypeScript, ESLint, build scripts
### 🚧 In Progress Components
- **Member Management**: Pages exist, but composables are stubs requiring completion
- **Site Structure**: Header/navigation complete, footer needs top section implementation
- **Event System**: CPTs ready, but calendar and mapping integration needed
- **Content Sections**: Basic system works, needs expansion of section types
### ⏳ Pending Integrations
- **Third-party Services**: Mailchimp, Stripe, AirTable integrations not implemented
- **Advanced Features**: Event subscriptions, premium memberships, admin tools
- **Performance**: Optimization, caching, and production readiness
- **Testing**: Comprehensive testing suite and quality assurance
### 🔥 Critical Next Steps
1. **Complete Member Area** - Finish useMemberSignup and useMemberArea composables (currently 49-byte stubs)
2. **Event Calendar Integration** - Implement Leaflet maps and calendar components
3. **Event-Representation Integration** - Display event instances via Event pages (backend relation)
4. **Footer Top Section** - Complete TheSiteFooter.vue implementation (currently shows "TODO")
---
## 📈 Future Roadmap
### Post-Launch Enhancements (Year 1)
- **Advanced Search**: Enhanced filtering and search capabilities
- **API Expansion**: Public API for third-party integrations
- **Analytics Dashboard**: Advanced reporting for admins
### Long-Term Vision (Years 2-3)
- **AI Features**: Content recommendations and smart matching
---
**Document Status**: Living document, updated regularly
**Last Updated**: September 25, 2025 - Comprehensive status analysis completed
**Current Phase**: Phase 2 (Core Features) - 70% complete
**Next Review**: Completion of site components and member management systems
**Critical Blocker**: Site components (header/footer/nav) must be completed before user testing
---
*This planning document serves as the north star for the CCAT project. All development decisions should align with the vision and principles outlined here.*

443
.claude/TASKS.md Normal file
View File

@@ -0,0 +1,443 @@
# TASKS.md - CCAT Project Task Management
## Task Status Instructions
Use GitHub-style checkboxes to mark task completion:
- `- [ ]` for uncompleted tasks
- `- [x]` for completed tasks
- Add notes or comments after tasks using `<!-- Notes: ... -->`
---
## Milestone 1: Foundation & Setup
### WordPress Theme Structure
- [x] Create basic WordPress theme structure with `functions.php` and `style.css` <!-- Completed: Basic files exist at wp-content/themes/ccat/ -->
- [x] Set up `composer.json` with WPackagist dependencies <!-- Completed: All required plugins installed via composer -->
- [x] Create directory structure (`acf-json/`, `includes/`, `app/`, `server/`, `shared/`) <!-- Completed: Full structure implemented -->
- [x] Configure Nuxt 4 within WordPress theme context <!-- Completed: nuxt.config.ts configured with all modules -->
- [x] Set up basic theme activation and WordPress integration <!-- Completed: functions.php includes all required files -->
### Development Environment
- [x] Configure Gitea Actions for CI/CD pipeline <!-- Completed: .gitea/workflows directory exists -->
- [x] Set up local development environment <!-- Completed: package.json with dev scripts -->
- [x] Configure environment variables for development/production <!-- Completed: .env file exists -->
- [x] Set up hot reloading for Nuxt within WordPress theme <!-- Completed: nuxt dev --host script configured -->
- [x] Create basic build scripts and deployment configuration <!-- Completed: build/deploy scripts in package.json -->
### Core Plugins & Dependencies
- [x] Install and configure WPGraphQL plugin <!-- Completed: wp-graphql in composer.json -->
- [x] Install and configure WPGraphQL JWT Authentication <!-- Completed: wp-graphql/wp-graphql-jwt-authentication installed -->
- [x] Install and configure Advanced Custom Fields (ACF) Pro <!-- Completed: advanced-custom-fields-pro 6.4.3 installed -->
- [x] Install and configure ACF Extended Pro <!-- Completed: acf-extended-pro installed -->
- [x] Configure GraphQL schema and test basic queries <!-- Completed: 866KB schema.graphql generated -->
---
## Milestone 2: Content Structure & Data Models
### Custom Post Types (CPT)
- [x] Create Contributor CPT (artist/organization profiles) <!-- Completed: includes/cpt/contributor.php -->
- [x] Create Event CPT (base event descriptions) <!-- Completed: includes/cpt/event.php -->
- [x] Create Listing CPT (job offers/proposals with deadlines) <!-- Completed: includes/cpt/listing.php -->
- [x] Create Location CPT (venue information, hierarchical) <!-- Completed: includes/cpt/location.php -->
- [x] Create Profile CPT (user cultural profiles) <!-- Completed: includes/cpt/profile.php -->
- [x] Create Project CPT (CCAT projects) <!-- Completed: includes/cpt/project.php -->
- [x] Create Representation CPT (event instances) <!-- Completed: includes/cpt/representation.php -->
- [x] Create Resource CPT (document/link repository) <!-- Completed: includes/cpt/resource.php -->
- [x] Create Template CPT (reusable content blocks) <!-- Completed: includes/cpt/template.php -->
### Custom Taxonomies
- [x] Create Discipline taxonomy (artistic/cultural categories) <!-- Completed: includes/taxonomies/discipline.php -->
- [x] Create Listing Category taxonomy <!-- Completed: includes/taxonomies/listing-category.php -->
- [x] Create Project Category taxonomy <!-- Completed: includes/taxonomies/project-category.php -->
- [x] Create Resource Category taxonomy <!-- Completed: includes/taxonomies/resource-category.php -->
- [x] Configure taxonomy relationships with CPTs <!-- Completed: All taxonomies configured in respective files -->
### ACF Field Groups
- [x] Design and create ACF fields for Contributor CPT <!-- Completed: group_post_contributor.json (11KB) -->
- [x] Design and create ACF fields for Event CPT <!-- Completed: group_post_event.json (11KB) -->
- [x] Design and create ACF fields for Listing CPT <!-- Completed: group_post_listing.json -->
- [x] Design and create ACF fields for Location CPT (venue/room hierarchy) <!-- Completed: group_post_location.json (11KB) -->
- [ ] Design and create ACF fields for Profile CPT <!-- Completed: group_post_profile.json (26KB) -->
- [x] Design and create ACF fields for Project CPT <!-- Completed: group_post_project.json (6KB) -->
- [x] Design and create ACF fields for Representation CPT <!-- Completed: group_post_representation.json (13KB) -->
- [x] Design and create ACF fields for Resource CPT <!-- Completed: group_post_resource.json (8KB) -->
- [x] Create flexible content field groups for dynamic layouts <!-- Completed: Multiple abstract groups (builder, credits, gallery, offer) -->
- [x] Set up ACF options page for site-wide settings <!-- Completed: group_options_page_ccat.json -->
### WPGraphQL Integration
- [x] Configure GraphQL schema for all CPTs <!-- Completed: All CPTs visible in 866KB schema.graphql -->
- [x] Configure GraphQL schema for all taxonomies <!-- Completed: All taxonomies in schema -->
- [x] Configure GraphQL schema for ACF fields <!-- Completed: wpgraphql-acf plugin configured -->
- [x] Test GraphQL queries for all content types <!-- Completed: Basic .gql files created -->
- [x] Set up GraphQL authentication and permissions <!-- Completed: JWT auth configured with includes/graphql/auth.php -->
- [x] Customize MediaItem GraphQL type to include center (x/y) fields <!-- Priority: High - Image cropping and point-of-interest support -->
---
## Milestone 3: Authentication & User Management
### JWT Authentication System
- [x] Configure JWT authentication for WPGraphQL <!-- Completed: wp-graphql-jwt-authentication installed and configured -->
- [x] Create `useAuth` composable for token management <!-- Completed: app/composables/useAuth.ts implemented -->
- [ ] Implement user registration flow <!-- Partial: registration structure exists, needs completion -->
- [x] Implement user login flow <!-- Completed: login.gql and AuthLoginForm.vue implemented -->
- [x] Implement JWT token refresh mechanism <!-- Completed: useUserSession with refresh in useAuth -->
- [x] Handle authentication errors and edge cases <!-- Completed: Error handling in useAuth composable -->
### User Roles & Permissions
- [x] Define custom user roles (member, premium, admin) <!-- Completed: hasRole middleware implemented -->
- [x] Configure user capabilities and permissions <!-- Completed: Role checking in useAuth -->
- [ ] Implement user registration with email verification <!-- Partial: registration structure exists -->
- [ ] Create user profile management system <!-- Partial: Profile CPT exists, management UI needed -->
- [ ] Link user accounts to Profile CPT <!-- Partial: Structure exists, linking logic needed -->
### Member Signup & Management
- [ ] Create `useMemberSignup` composable <!-- Critical: Current file is stub (49 bytes) - needs full implementation -->
- [ ] Create `useMemberArea` composable <!-- Critical: Current file is stub (49 bytes) - needs full implementation -->
- [ ] Build member registration forms <!-- Priority: High - devenir-membre.vue page exists but needs completion -->
- [ ] Build member profile editing interface <!-- Priority: High - espace-membre.vue page exists but needs completion -->
- [ ] Implement membership tier upgrades <!-- Priority: Medium - Business logic needed -->
- [x] Create admin user impersonation functionality <!-- Completed: switchTo.gql and isSwitchedTo in useAuth -->
---
## Milestone 4: Core Nuxt Components
### Base Component Architecture
- [ ] Set up Nuxt UI integration
- [ ] Create base layout structure
- [ ] Design component organization system
### Node Components (Main Page Components)
- [x] Create node component for Event pages <!-- Completed: app/components/nodes/TheEvent.vue -->
- [x] Create node component for Listing pages <!-- Completed: app/components/nodes/TheListing.vue -->
- [x] Create node component for Location pages <!-- Completed: app/components/nodes/TheLocation.vue -->
- [x] Create node component for Profile pages <!-- Completed: app/components/nodes/TheProfile.vue -->
- [x] Create node component for Project pages <!-- Completed: app/components/nodes/TheProject.vue -->
- [x] Create node component for Resource pages <!-- Completed: app/components/nodes/TheResource.vue -->
- [x] Create `useNodeByUri` composable for content fetching <!-- Completed: app/composables/useNodeByUri.ts -->
### Site Components (Global)
- [x] Create header component with navigation <!-- Completed: TheSiteHeader.vue with UHeader and navigation menu -->
- [ ] Create footer component <!-- Partial: TheSiteFooter.vue exists but only shows "TODO" - needs top part implementation -->
- [x] Create main navigation system <!-- Completed: UNavigationMenu integrated with useMenuItems composable -->
- [x] Create breadcrumb navigation (excluding virtual pages) <!-- Completed: SiteBreadcrumbs.vue and includes/graphql/breadcrumbs.php -->
- [ ] Create search functionality <!-- Priority: Medium - Enhanced user experience -->
- [x] Implement responsive navigation for mobile <!-- Completed: slideover mode in UHeader with responsive breakpoints -->
### Authentication Components
- [x] Create login form component <!-- Completed: app/components/auth/AuthLoginForm.vue -->
- [ ] Create registration form component <!-- Partial: Structure exists, needs completion -->
- [ ] Create password reset component
- [x] Create protected route middleware <!-- Completed: hasRole.ts, isAdmin.ts, isLoggedIn.ts, isLoggedOut.ts -->
- [ ] Create user profile components <!-- Partial: Profile node exists -->
- [ ] Create member zone dashboard <!-- Partial: espace-membre.vue page exists -->
---
## Milestone 5: Content Management & Flexible Layouts
### Flexible Content Sections
- [x] Create section components for ACF flexible fields <!-- Completed: Basic sections (TextBlock, Wrapper) -->
- [x] Design reusable content block system <!-- Completed: TheSection.fragment.gql and TheSections.vue -->
- [x] Implement Template CPT integration <!-- Completed: Template CPT created -->
- [x] Create dynamic section rendering system <!-- Completed: TheSections.vue handles dynamic rendering -->
- [x] Implement section preview in admin <!-- Priority: Low - Enhanced admin experience -->
- [ ] Create additional section components (Hero, Gallery, CTA, etc.) <!-- Priority: Medium - Expand content flexibility -->
- [ ] Add shared section settings (container width, color theme, etc.) <!-- Priority: Medium - Design flexibility -->
### ACF Extended Pro Preview System
- [x] Configure ACF Extended Pro preview templates <!-- Completed: ACF Extended Pro installed -->
- [x] Set up iframe preview system <!-- Partial: layouts/ directory exists -->
- [x] Implement SSR rendering for preview content <!-- Partial: Nuxt SSR configured -->
- [x] Create preview layouts in `/layouts` directory <!-- Completed: layouts/ directory with files -->
- [x] Implement reusable template replacement logic
- [x] Test real-time preview functionality
### Content Features
- [x] Implement image uploads with point-of-interest cropping
- [x] Implement virtual pages (redirect to first child)
- [ ] Create automated URL redirect system
- [ ] Build content search and filtering
- [ ] Create content categorization system
- [ ] Handle richtext content display on frontend <!-- Priority: High - Hijack links for Nuxt navigation, use NuxtImg for images -->
### Missing Core Components
- [x] Create TheContributor node component <!-- Not needed: Contributor is backend-only, not publicly displayed -->
- [x] Create TheRepresentation node component <!-- Not needed: Representation is backend-only, handled via Event display -->
- [x] Implement menu system integration <!-- Completed: useMenuItems integrated in TheSiteHeader.vue -->
- [ ] Create user management components for profiles <!-- Priority: High - Profile editing interface -->
- [ ] Build admin dashboard components <!-- Priority: Medium - Staff management tools -->
- [ ] Complete footer top section implementation <!-- Priority: Medium - TheSiteFooter.vue needs content above bottom part -->
---
## Milestone 6: Event System & Calendar
### Event Management
- [x] Design event-representation relationship system <!-- Completed: CPTs created with proper relationships -->
- [ ] Create event creation and editing interface <!-- Priority: High - User content creation -->
- [ ] Build event listing and detail pages <!-- Priority: High - Core event functionality -->
- [ ] Implement event approval workflow for admins <!-- Priority: Medium - Content moderation -->
- [ ] Create event search and filtering system <!-- Priority: High - User discovery -->
### Interactive Calendar
- [ ] Integrate Leaflet maps for location display <!-- Priority: High - Location visualization -->
- [ ] Build calendar component with multiple views (month/week/day/list) <!-- Priority: High - Core calendar functionality -->
- [ ] Implement event filtering and search <!-- Priority: High - User experience -->
- [ ] Create event detail modal/popup <!-- Priority: High - Event details display -->
- [ ] Add calendar navigation and date selection <!-- Priority: High - Calendar interaction -->
- [ ] Connect events to representations for calendar display <!-- Priority: Critical - Link event instances -->
- [ ] Add location markers on map integration <!-- Priority: Medium - Enhanced location display -->
### Event Subscriptions
- [ ] Design event subscription system
- [ ] Create subscription forms (free events)
- [ ] Implement waitlist management
- [ ] Build bulk attendee registration for admins
- [ ] Create subscription confirmation system
- [ ] Add subscription cancellation functionality
---
## Milestone 7: Utilities & Composables
### Core Composables
- [x] Create `useResponsive` composable for responsive utilities <!-- Completed: app/composables/useResponsive.ts -->
- [x] Create `useSiteOptions` composable for ACF options page <!-- Completed: app/composables/useSiteOptions.ts -->
- [ ] Build error handling utilities <!-- Partial: Basic error handling in useAuth -->
- [ ] Create loading state management <!-- Partial: Some loading states exist -->
- [ ] Implement cache management utilities
### GraphQL Operations
- [x] Create GraphQL operation files (`.gql`) in `/app/graphql/` <!-- Completed: 5 .gql files created -->
- [ ] Set up GraphQL codegen for TypeScript types <!-- Partial: nuxt-graphql-middleware configured -->
- [x] Create reusable GraphQL fragments <!-- Completed: Fragment files for components -->
- [ ] Implement GraphQL error handling <!-- Partial: Basic handling exists -->
- [ ] Add GraphQL query optimization <!-- Needs assessment and optimization -->
- [ ] Create GraphQL operations for all CPTs <!-- Priority: High - Missing operations for many CPTs -->
- [ ] Implement pagination for large datasets <!-- Priority: Medium - Performance optimization -->
- [ ] Add GraphQL subscriptions for real-time updates <!-- Priority: Low - Future enhancement -->
---
## Milestone 8: Third-Party Integrations (PHP)
### Mailchimp Integration
- [ ] Set up Mailchimp PHP SDK
- [ ] Create user synchronization system
- [ ] Implement newsletter subscription management
- [ ] Build transactional email system
- [ ] Create email template system
- [ ] Add merge field synchronization
### Stripe Integration
- [ ] Set up Stripe PHP SDK
- [ ] Implement payment processing for premium memberships
- [ ] Create subscription billing system
- [ ] Build payment webhook handling
- [ ] Implement refund processing
- [ ] Add payment analytics and reporting
### AirTable Import System
- [ ] Design non-destructive import system
- [ ] Create AirTable API integration
- [ ] Build field mapping interface
- [ ] Implement incremental updates
- [ ] Add import validation and error handling
- [ ] Create import history and rollback functionality
---
## Milestone 9: Advanced Features
### Admin Tools
- [ ] Create admin dashboard
- [ ] Build user management interface
- [ ] Implement content moderation tools
- [ ] Create event subscription management
- [ ] Add analytics and reporting features
- [ ] Build system configuration interface
### Event Webscraping Tool
- [ ] Design webscraping architecture
- [ ] Create external event source configuration
- [ ] Build automated event discovery system
- [ ] Implement data validation and normalization
- [ ] Add duplicate detection and management
- [ ] Create admin review and approval workflow
### Premium Membership Features
- [ ] Design premium feature system
- [ ] Enhanced profile visibility
- [ ] Priority event listings
- [ ] Advanced analytics for members
- [ ] Additional content creation tools
- [ ] Premium support features
---
## Milestone 10: Additional Implementations
### Missing UI Components
- [ ] Create custom form components for user-generated content <!-- Priority: High - User interaction -->
- [ ] Build notification/toast system <!-- Priority: Medium - User feedback -->
- [ ] Create loading states and skeleton screens <!-- Priority: Medium - User experience -->
- [ ] Implement modal/dialog system <!-- Priority: Medium - Interactions -->
- [ ] Build file upload components with progress <!-- Priority: Medium - Media management -->
- [ ] Create responsive tables for admin data <!-- Priority: Low - Admin experience -->
### Enhanced Features
- [ ] Add real-time validation for forms <!-- Priority: Medium - User experience -->
- [ ] Implement advanced search with filters <!-- Priority: Medium - Content discovery -->
- [ ] Create bookmark/favorite system for events <!-- Priority: Low - User engagement -->
- [ ] Add social sharing components <!-- Priority: Low - Content promotion -->
- [ ] Implement print-friendly views <!-- Priority: Low - Accessibility -->
### SEO & Performance
- [ ] Generate dynamic sitemap.xml for all public content <!-- Priority: Medium - SEO optimization - Include all CPTs, taxonomies, and pages with proper priorities and change frequencies -->
---
## Milestone 11: UI/UX & Polish
### Custom UI Components
- [ ] Design and build custom UI component library
- [ ] Create consistent styling system
- [ ] Implement responsive design patterns
- [ ] Add animations and transitions
- [ ] Build accessibility features
- [ ] Create component documentation
### Mobile Optimization
- [ ] Optimize all components for mobile
- [ ] Implement touch-friendly interactions
- [ ] Create mobile-specific navigation
- [ ] Optimize performance for mobile devices
- [ ] Test across different screen sizes
---
## Milestone 11: Testing & Quality Assurance
### Unit Testing
- [ ] Set up testing framework
- [ ] Write tests for composables
- [ ] Test utility functions
- [ ] Create mock data for testing
- [ ] Add continuous integration testing
### Integration Testing
- [ ] Test GraphQL operations
- [ ] Test WordPress/PHP integration
- [ ] Validate third-party integrations
- [ ] Test user authentication flows
- [ ] Verify payment processing
### End-to-End Testing
- [ ] Test complete user registration flow
- [ ] Test event creation and subscription
- [ ] Test member area functionality
- [ ] Test admin workflows
- [ ] Test content preview system
---
## Milestone 12: Performance & Optimization
### Performance Optimization
- [ ] Optimize GraphQL queries (prevent N+1)
- [ ] Implement caching strategies
- [ ] Optimize images with @nuxt/image
- [ ] Minimize bundle sizes
- [ ] Implement lazy loading
- [ ] Monitor Core Web Vitals
### Security Audit
- [ ] Review authentication security
- [ ] Validate input sanitization
- [ ] Test API security
- [ ] Review payment security
- [ ] Implement security headers
- [ ] Run security vulnerability scans
---
## Milestone 13: Launch Preparation
### Content Migration
- [ ] Migrate existing content from current systems
- [ ] Set up initial user accounts
- [ ] Import event data
- [ ] Configure site-wide settings
- [ ] Test content import process
### Documentation & Training
- [ ] Create user documentation
- [ ] Write admin training materials
- [ ] Document API endpoints
- [ ] Create troubleshooting guides
- [ ] Record training videos
### Final Testing & Deployment
- [ ] Complete end-to-end testing
- [ ] Performance testing under load
- [ ] Cross-browser compatibility testing
- [ ] Mobile device testing
- [ ] Production deployment
- [ ] Post-launch monitoring setup
---
### Current Technical Debt
- [ ] Implement complete member signup flow <!-- Priority: High - useMemberSignup.ts is stub -->
- [ ] Complete member area functionality <!-- Priority: High - useMemberArea.ts is stub -->
- [ ] Add comprehensive error boundaries <!-- Priority: Medium - Application stability -->
- [ ] Implement proper loading states across app <!-- Priority: Medium - User experience -->
- [ ] Add input validation and sanitization <!-- Priority: High - Security -->
- [ ] Create comprehensive TypeScript types <!-- Priority: Medium - Development experience -->
---
## Post-Launch Tasks
### Ongoing Maintenance
- [ ] Set up monitoring and alerting <!-- Priority: High - Production readiness -->
- [ ] Create backup procedures <!-- Priority: High - Data protection -->
- [ ] Plan regular security updates <!-- Priority: High - Security maintenance -->
- [ ] Monitor performance metrics <!-- Priority: High - Performance tracking -->
- [ ] Gather user feedback <!-- Priority: Medium - Continuous improvement -->
- [ ] Plan feature iterations <!-- Priority: Medium - Product evolution -->
---
---
## Current Status Summary (Updated)
### ✅ Completed Phases:
- **Foundation & Setup**: ~95% complete (Milestone 1)
- **Content Structure**: ~90% complete (Milestone 2)
- **Authentication Core**: ~80% complete (Milestone 3)
- **Basic Components**: ~70% complete (Milestone 4)
### 🚧 In Progress:
- **Content Management**: ~60% complete (Milestone 5)
- **Core Composables**: ~70% complete (Milestone 7)
### ⏳ Next Priority Areas:
1. **Member Area Completion** - Critical (useMemberSignup & useMemberArea composables)
2. **Event System Implementation** - High Priority (including backend Representation data)
3. **Event Calendar Integration** - High Priority (Leaflet maps)
4. **Footer Completion** - Medium Priority (TheSiteFooter top section)
5. **Third-party Integrations** - Medium Priority
### 📊 Overall Project Status: ~65% Complete
**Notes:**
- Mark completed tasks with `[x]`
- Add comments or blockers using `<!-- Notes: ... -->` after tasks
- Update this file regularly during development
- Use this file to track progress and plan work sessions
- Priority levels: Critical > High > Medium > Low

View File

@@ -1,7 +1,11 @@
name: WordPress deployment
name: Deploy WordPress and Nuxt
run-name: ${{ gitea.actor }} deploying ${{ gitea.repository.name }}
on: [push]
env:
NUXT_PROJECT_PATH: wp-content/themes/ccat
PNPM_STORE_DIR: /cache/wp-scripts/pnpm
jobs:
deploy:
runs-on: ubuntu-websimple
@@ -15,11 +19,22 @@ jobs:
run: |
git clone https://$TEMPLATES_REPO_TOKEN@gitea.websimple.com/templates/wp-scripts.git /tmp/wp-scripts
- name: Run deployment script
- name: Deploy WordPress
env:
REMOTE_HOST: ${{ vars.REMOTE_HOST }}
REMOTE_PORT: ${{ vars.REMOTE_PORT }}
REMOTE_USER: ${{ vars.REMOTE_USER }}
REMOTE_PATH: ${{ vars.REMOTE_PATH }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: /tmp/wp-scripts/wp-deploy.sh
run: /tmp/wp-scripts/wp-deploy.sh --skip-node
- name: Install Node.js dependencies
working-directory: ${{ env.NUXT_PROJECT_PATH }}
run: pnpm install --store-dir=${{ env.PNPM_STORE_DIR }}
- name: Deploy to NuxtHub
working-directory: ${{ env.NUXT_PROJECT_PATH }}
env:
NUXT_HUB_PROJECT_KEY: ${{ vars.NUXT_HUB_PROJECT_KEY }}
NUXT_HUB_USER_TOKEN: ${{ secrets.NUXT_HUB_USER_TOKEN }}
run: pnpx nuxthub@latest deploy

4
.gitignore vendored
View File

@@ -1,8 +1,8 @@
/*
!/.claude
!/.gitea
!/.gitignore
!/.vscode/
!/CLAUDE.md
!/composer.*
!/phpcs.xml
!/wp-content/
@@ -19,3 +19,5 @@
/wp-content/themes/*
!/wp-content/themes/.gitkeep
!/wp-content/themes/ccat/
.data

39
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,39 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
{
"type": "firefox",
"request": "launch",
"name": "Nuxt client",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/wp-content/themes/ccat",
"pathMappings": [
{
"url": "http://localhost:3000/_nuxt/",
"path": "${workspaceFolder}/wp-content/themes/ccat"
}
]
},
{
"name": "Nuxt server",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}/wp-content/themes/ccat",
"runtimeExecutable": "pnpm",
"runtimeArgs": [
"dev"
]
}
],
"compounds": [
{
"name": "Nuxt fullstack",
"configurations": [
"Nuxt server",
"Nuxt client"
]
}
]
}

View File

@@ -19,18 +19,19 @@
"sort-packages": true
},
"require": {
"axepress/wp-graphql-rank-math": "*",
"lewebsimple/acf-extended-pro": "*",
"lewebsimple/acf-polylang": "*",
"lewebsimple/admin-site-enhancements-pro": "*",
"lewebsimple/advanced-custom-fields-pro": "6.4.3",
"lewebsimple/ithemes-security-pro": "*",
"lewebsimple/kaliroots": "*",
"lewebsimple/rank-math-pro": "*",
"lewebsimple/theia-smart-thumbnails-premium": "*",
"lewebsimple/wp-offload-ses": "*",
"wp-graphql/wp-graphql-jwt-authentication": "*",
"wpackagist-plugin/clean-image-filenames": "*",
"wpackagist-plugin/disable-comments": "*",
"wpackagist-plugin/redirection": "*",
"wpackagist-plugin/user-switching": "*",
"wpackagist-plugin/wp-graphql": "*",
"wpackagist-plugin/wpgraphql-acf": "*"
}

271
composer.lock generated
View File

@@ -4,8 +4,169 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7404139a6c60217cf6e5f80ac88be31f",
"content-hash": "a2f8ce11c2aa318d143b38ac84862305",
"packages": [
{
"name": "axepress/wp-graphql-plugin-boilerplate",
"version": "0.1.1",
"source": {
"type": "git",
"url": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate.git",
"reference": "09495b61346453baabdf4c71a38ada3cfc91c3a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/AxeWP/wp-graphql-plugin-boilerplate/zipball/09495b61346453baabdf4c71a38ada3cfc91c3a7",
"reference": "09495b61346453baabdf4c71a38ada3cfc91c3a7",
"shasum": ""
},
"require": {
"php": ">=7.4"
},
"require-dev": {
"axepress/wp-graphql-cs": "^2.0.0",
"axepress/wp-graphql-stubs": "^2.3.0",
"phpcompatibility/php-compatibility": "dev-develop as 9.9.9",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-deprecation-rules": "^2.0.1",
"szepeviktor/phpstan-wordpress": "^2.0",
"wp-cli/wp-cli-bundle": "^2.8.1"
},
"type": "library",
"autoload": {
"psr-4": {
"AxeWP\\GraphQL\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0-or-later"
],
"authors": [
{
"name": "AxePress Development",
"homepage": "https://axepress.dev"
},
{
"name": "David Levine",
"role": "Developer"
}
],
"description": "Boilerplate for creating WPGraphQL extensions",
"support": {
"issues": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate/issues",
"source": "https://github.com/AxeWP/wp-graphql-plugin-boilerplate/tree/0.1.1"
},
"funding": [
{
"url": "https://github.com/AxeWp",
"type": "github"
}
],
"time": "2025-06-07T02:03:50+00:00"
},
{
"name": "axepress/wp-graphql-rank-math",
"version": "0.3.4",
"source": {
"type": "git",
"url": "https://github.com/AxeWP/wp-graphql-rank-math.git",
"reference": "167bdd4a5350717ed34069c304e0ffc3fe02bc7d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/AxeWP/wp-graphql-rank-math/zipball/167bdd4a5350717ed34069c304e0ffc3fe02bc7d",
"reference": "167bdd4a5350717ed34069c304e0ffc3fe02bc7d",
"shasum": ""
},
"require": {
"axepress/wp-graphql-plugin-boilerplate": "^0.1.1",
"php": ">=7.4"
},
"require-dev": {
"axepress/wp-graphql-cs": "^2.0.0",
"axepress/wp-graphql-stubs": "^2.0.0",
"codeception/lib-innerbrowser": "^1.0",
"codeception/module-asserts": "^1.0",
"codeception/module-cli": "^1.0",
"codeception/module-db": "^1.0",
"codeception/module-filesystem": "^1.0",
"codeception/module-phpbrowser": "^1.0",
"codeception/module-rest": "^2.0",
"codeception/module-webdriver": "^1.0",
"codeception/phpunit-wrapper": "^9.0",
"codeception/util-universalframework": "^1.0",
"lucatume/wp-browser": "<3.5",
"php-coveralls/php-coveralls": "^2.5",
"phpcompatibility/php-compatibility": "dev-develop as 9.9.9",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^2.1.5",
"phpunit/phpunit": "^9.5",
"szepeviktor/phpstan-wordpress": "^2.0.1",
"wp-cli/wp-cli-bundle": "^2.8.1",
"wp-graphql/wp-graphql-testcase": "~3.4.0"
},
"type": "wordpress-plugin",
"extra": {
"strauss": {
"packages": [
"axepress/wp-graphql-plugin-boilerplate"
],
"classmap_prefix": "WPGraphQL_RankMath_",
"constant_prefix": "WPGRAPHQL_SEO_",
"namespace_prefix": "WPGraphQL\\RankMath\\Vendor\\",
"target_directory": "vendor-prefixed",
"update_call_sites": false,
"exclude_from_prefix": {
"namespaces": [],
"file_patterns": []
},
"include_modified_date": false,
"delete_vendor_packages": true
}
},
"autoload": {
"files": [
"access-functions.php"
],
"psr-4": {
"WPGraphQL\\RankMath\\": "src/"
},
"classmap": [
"vendor-prefixed/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0-or-later"
],
"authors": [
{
"name": "AxePress Development",
"email": "support@axepress.dev",
"homepage": "https://axepress.dev"
},
{
"name": "David Levine",
"role": "Developer"
}
],
"description": "Adds WPGraphQL support for RankMath SEO",
"support": {
"email": "support@axepress.dev",
"forum": "https://github.com/AxeWP/wp-graphql-rank-math/discussions",
"issues": "https://github.com/AxeWP/wp-graphql-rank-math/issues",
"source": "https://github.com/AxeWP/wp-graphql-rank-math/tree/0.3.4"
},
"funding": [
{
"url": "https://github.com/sponsors/AxeWP",
"type": "github"
}
],
"time": "2025-06-07T12:05:15+00:00"
},
{
"name": "composer/installers",
"version": "v2.3.0",
@@ -217,27 +378,27 @@
},
{
"name": "lewebsimple/acf-extended-pro",
"version": "v0.9.1",
"version": "v0.9.1.1",
"source": {
"type": "git",
"url": "ssh://git@gitlab.ledevsimple.ca:222/wp-plugins/acf-extended-pro.git",
"reference": "123a9cb62feeb020b495f9963ce0c78529970d89"
"url": "ssh://git@gitea.websimple.com:222/wp-plugins/acf-extended-pro.git",
"reference": "83b6ccef59c5580042c2a144921c0c55c44f3963"
},
"dist": {
"type": "zip",
"url": "https://satis.ledevsimple.ca/dist/lewebsimple/acf-extended-pro/lewebsimple-acf-extended-pro-v0.9.1-72f8d5.zip",
"reference": "123a9cb62feeb020b495f9963ce0c78529970d89",
"shasum": "9fb98d03a632cd9310c32cb7185431ebce6cc337"
"url": "https://satis.ledevsimple.ca/dist/lewebsimple/acf-extended-pro/lewebsimple-acf-extended-pro-v0.9.1.1-8eea9e.zip",
"reference": "83b6ccef59c5580042c2a144921c0c55c44f3963",
"shasum": "af562265aa563b0f8884df84abb64aac5e73764d"
},
"type": "wordpress-plugin",
"time": "2025-02-25T14:28:04+00:00"
"time": "2025-09-24T11:56:37+00:00"
},
{
"name": "lewebsimple/acf-polylang",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "ssh://git@gitlab.ledevsimple.ca:222/wp-plugins/acf-polylang.git",
"url": "ssh://git@gitea.websimple.com:222/wp-plugins/acf-polylang.git",
"reference": "3998e44ccc400bd6233c98364df03a4f6db4f7b0"
},
"dist": {
@@ -254,7 +415,7 @@
"version": "v7.9.2",
"source": {
"type": "git",
"url": "ssh://git@gitlab.ledevsimple.ca:222/wp-plugins/admin-site-enhancements-pro.git",
"url": "ssh://git@gitea.websimple.com:222/wp-plugins/admin-site-enhancements-pro.git",
"reference": "01b95e4a6da08543cd69b0d30485b221e032352e"
},
"dist": {
@@ -271,7 +432,7 @@
"version": "v6.4.3",
"source": {
"type": "git",
"url": "ssh://git@gitlab.ledevsimple.ca:222/wp-plugins/advanced-custom-fields-pro.git",
"url": "ssh://git@gitea.websimple.com:222/wp-plugins/advanced-custom-fields-pro.git",
"reference": "9e4bb1f624589e4718cb4b58e44916ebc859f659"
},
"dist": {
@@ -288,7 +449,7 @@
"version": "v8.5.8",
"source": {
"type": "git",
"url": "ssh://git@gitlab.ledevsimple.ca:222/wp-plugins/ithemes-security-pro.git",
"url": "ssh://git@gitea.websimple.com:222/wp-plugins/ithemes-security-pro.git",
"reference": "d9b6bd9368baef4b8775928c04eaa5d1bdfb004d"
},
"dist": {
@@ -305,7 +466,7 @@
"version": "v0.9.17",
"source": {
"type": "git",
"url": "ssh://git@gitlab.ledevsimple.ca:222/wp-themes/kaliroots.git",
"url": "ssh://git@gitea.websimple.com:222/wp-themes/kaliroots.git",
"reference": "a9cf1340420b4c36800e67dbb6641141d1d27b9b"
},
"dist": {
@@ -317,12 +478,46 @@
"type": "wordpress-theme",
"time": "2025-04-10T12:17:27+00:00"
},
{
"name": "lewebsimple/rank-math-pro",
"version": "v3.0.96",
"source": {
"type": "git",
"url": "ssh://git@gitea.websimple.com:222/wp-plugins/rank-math-pro.git",
"reference": "1460cc2b26bf74b2dc34210d75ba47362c936778"
},
"dist": {
"type": "zip",
"url": "https://satis.ledevsimple.ca/dist/lewebsimple/rank-math-pro/lewebsimple-rank-math-pro-v3.0.96-2ffc77.zip",
"reference": "1460cc2b26bf74b2dc34210d75ba47362c936778",
"shasum": "052e62a8f1ab5520928a04b2281c57b0978999b4"
},
"type": "wordpress-plugin",
"time": "2025-09-26T02:08:49+00:00"
},
{
"name": "lewebsimple/theia-smart-thumbnails-premium",
"version": "v2.3.0.1",
"source": {
"type": "git",
"url": "ssh://git@gitea.websimple.com:222/wp-plugins/theia-smart-thumbnails-premium.git",
"reference": "77e2eb966434c1d5bd18dcd2f2948f0efd2aaf36"
},
"dist": {
"type": "zip",
"url": "https://satis.ledevsimple.ca/dist/lewebsimple/theia-smart-thumbnails-premium/lewebsimple-theia-smart-thumbnails-premium-v2.3.0.1-8e24d0.zip",
"reference": "77e2eb966434c1d5bd18dcd2f2948f0efd2aaf36",
"shasum": "e453c7b9d3bffcf1c0bc2104b495aa57425a8b52"
},
"type": "wordpress-plugin",
"time": "2024-02-26T18:35:09+00:00"
},
{
"name": "lewebsimple/wp-offload-ses",
"version": "v1.6.8",
"source": {
"type": "git",
"url": "ssh://git@gitlab.ledevsimple.ca:222/wp-plugins/wp-offload-ses.git",
"url": "ssh://git@gitea.websimple.com:222/wp-plugins/wp-offload-ses.git",
"reference": "7b6046d329e96da3a5f6714cd73e14172d9e7840"
},
"dist": {
@@ -409,15 +604,15 @@
},
{
"name": "wpackagist-plugin/disable-comments",
"version": "2.5.2",
"version": "2.5.3",
"source": {
"type": "svn",
"url": "https://plugins.svn.wordpress.org/disable-comments/",
"reference": "tags/2.5.2"
"reference": "tags/2.5.3"
},
"dist": {
"type": "zip",
"url": "https://downloads.wordpress.org/plugin/disable-comments.2.5.2.zip"
"url": "https://downloads.wordpress.org/plugin/disable-comments.2.5.3.zip"
},
"require": {
"composer/installers": "^1.0 || ^2.0"
@@ -425,53 +620,17 @@
"type": "wordpress-plugin",
"homepage": "https://wordpress.org/plugins/disable-comments/"
},
{
"name": "wpackagist-plugin/redirection",
"version": "5.5.2",
"source": {
"type": "svn",
"url": "https://plugins.svn.wordpress.org/redirection/",
"reference": "tags/5.5.2"
},
"dist": {
"type": "zip",
"url": "https://downloads.wordpress.org/plugin/redirection.5.5.2.zip"
},
"require": {
"composer/installers": "^1.0 || ^2.0"
},
"type": "wordpress-plugin",
"homepage": "https://wordpress.org/plugins/redirection/"
},
{
"name": "wpackagist-plugin/user-switching",
"version": "1.10.0",
"source": {
"type": "svn",
"url": "https://plugins.svn.wordpress.org/user-switching/",
"reference": "tags/1.10.0"
},
"dist": {
"type": "zip",
"url": "https://downloads.wordpress.org/plugin/user-switching.1.10.0.zip"
},
"require": {
"composer/installers": "^1.0 || ^2.0"
},
"type": "wordpress-plugin",
"homepage": "https://wordpress.org/plugins/user-switching/"
},
{
"name": "wpackagist-plugin/wp-graphql",
"version": "2.3.3",
"version": "2.3.6",
"source": {
"type": "svn",
"url": "https://plugins.svn.wordpress.org/wp-graphql/",
"reference": "tags/2.3.3"
"reference": "tags/2.3.6"
},
"dist": {
"type": "zip",
"url": "https://downloads.wordpress.org/plugin/wp-graphql.2.3.3.zip"
"url": "https://downloads.wordpress.org/plugin/wp-graphql.2.3.6.zip"
},
"require": {
"composer/installers": "^1.0 || ^2.0"

View File

@@ -40,6 +40,7 @@
<exclude name="WordPress.DB.SlowDBQuery.slow_db_query_tax_query"/>
<exclude name="WordPress.Files.FileName.NotHyphenatedLowercase"/>
<exclude name="WordPress.NamingConventions.ValidHookName.UseUnderscores"/>
<exclude name="WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase"/>
<exclude name="WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode"/>
<exclude name="WordPress.PHP.StrictInArray.MissingTrueStrict"/>
<exclude name="WordPress.PHP.YodaConditions.NotYoda"/>

View File

@@ -0,0 +1,10 @@
<?php
// Map WordPress home URL to the public frontend domain
add_filter( 'home_url', 'ccat_headless_home_url' );
function ccat_headless_home_url( $url ) {
if ( is_admin() || wp_doing_cron() || defined( 'WP_CLI' ) ) {
return $url;
}
return str_replace( 'wp.cultureat.ca', 'cultureat.ca', $url );
}

View File

@@ -4,6 +4,7 @@
.nuxt
.nitro
.cache
.wrangler
dist
# Node dependencies
@@ -22,5 +23,3 @@ logs
.env
.env.*
!.env.example
.wrangler

View File

@@ -0,0 +1 @@
shamefully-hoist=true

View File

@@ -0,0 +1,3 @@
# cultureat.ca
Site web du Conseil de la culture de l'Abitibi-Témiscamingue.

View File

@@ -1,10 +1,19 @@
<?php
__( "1024px container", 'ccat' );
__( "1280px container", 'ccat' );
__( "640px container", 'ccat' );
__( "768px container", 'ccat' );
__( "Abstract &#8211; Address (city)", 'ccat' );
__( "Abstract &#8211; Address (contact)", 'ccat' );
__( "Abstract &#8211; Address (geo)", 'ccat' );
__( "Abstract &#8211; Builder", 'ccat' );
__( "Abstract &#8211; Contact", 'ccat' );
__( "Abstract &#8211; Credits", 'ccat' );
__( "Abstract &#8211; Entity", 'ccat' );
__( "Abstract &#8211; Gallery", 'ccat' );
__( "Abstract &#8211; Offer", 'ccat' );
__( "Abstract &#8211; Social", 'ccat' );
__( "Accented background", 'ccat' );
__( "Add File", 'ccat' );
__( "Address", 'ccat' );
__( "Adultes (18+)", 'ccat' );
@@ -12,18 +21,22 @@ __( "Ajouter un élément", 'ccat' );
__( "Alternative title(s)", 'ccat' );
__( "Attendance mode", 'ccat' );
__( "Auteur", 'ccat' );
__( "Background color", 'ccat' );
__( "Bar", 'ccat' );
__( "Billing", 'ccat' );
__( "Billing is the same as contact", 'ccat' );
__( "Builder", 'ccat' );
__( "Cancelled", 'ccat' );
__( "Categorie(s)", 'ccat' );
__( "Category", 'ccat' );
__( "Collectif artistique", 'ccat' );
__( "Complete", 'ccat' );
__( "Compositeur", 'ccat' );
__( "Configuration", 'ccat' );
__( "Configuration name", 'ccat' );
__( "Confirmed", 'ccat' );
__( "Contact", 'ccat' );
__( "Content", 'ccat' );
__( "Content width", 'ccat' );
__( "Contribution type(s)", 'ccat' );
__( "Contribution(s)", 'ccat' );
__( "Contributor", 'ccat' );
@@ -32,10 +45,13 @@ __( "Credits", 'ccat' );
__( "Date / time", 'ccat' );
__( "Date range", 'ccat' );
__( "Day(s)", 'ccat' );
__( "Default background", 'ccat' );
__( "Default container", 'ccat' );
__( "Description", 'ccat' );
__( "Discipline(s)", 'ccat' );
__( "Document type", 'ccat' );
__( "Document(s)", 'ccat' );
__( "Elevated background", 'ccat' );
__( "Email", 'ccat' );
__( "Email preferences", 'ccat' );
__( "End date", 'ccat' );
@@ -51,43 +67,44 @@ __( "Failed", 'ccat' );
__( "Familial", 'ccat' );
__( "Festival", 'ccat' );
__( "File", 'ccat' );
__( "First name", 'ccat' );
__( "Fluid container", 'ccat' );
__( "Form", 'ccat' );
__( "Free", 'ccat' );
__( "Full-width container", 'ccat' );
__( "Gallery", 'ccat' );
__( "H:i", 'ccat' );
__( "Hybrid", 'ccat' );
__( "Identifier(s)", 'ccat' );
__( "Image", 'ccat' );
__( "In-person", 'ccat' );
__( "Individu", 'ccat' );
__( "Individual day(s)", 'ccat' );
__( "Individual profile", 'ccat' );
__( "Institution", 'ccat' );
__( "Interprète", 'ccat' );
__( "Is asynchronous", 'ccat' );
__( "Language(s)", 'ccat' );
__( "Locality", 'ccat' );
__( "Last name", 'ccat' );
__( "Localities", 'ccat' );
__( "Location", 'ccat' );
__( "Location type", 'ccat' );
__( "MRC", 'ccat' );
__( "Managed contributor", 'ccat' );
__( "Media type", 'ccat' );
__( "Media(s)", 'ccat' );
__( "Membership plan", 'ccat' );
__( "Membership(s)", 'ccat' );
__( "Membre (individu)", 'ccat' );
__( "Membre (organisation)", 'ccat' );
__( "Message", 'ccat' );
__( "Minimum price", 'ccat' );
__( "Moral entity", 'ccat' );
__( "Multiple day(s)", 'ccat' );
__( "Muted background", 'ccat' );
__( "Name", 'ccat' );
__( "Notification(s)", 'ccat' );
__( "Offer", 'ccat' );
__( "Offer status", 'ccat' );
__( "Online", 'ccat' );
__( "Options page &#8211; CCAT", 'ccat' );
__( "Organization profile", 'ccat' );
__( "Organisation", 'ccat' );
__( "Period", 'ccat' );
__( "Person name", 'ccat' );
__( "Phone", 'ccat' );
__( "Physical person", 'ccat' );
__( "Planned", 'ccat' );
@@ -95,22 +112,29 @@ __( "Possible configuration(s)", 'ccat' );
__( "Post &#8211; Article", 'ccat' );
__( "Post &#8211; Contributor", 'ccat' );
__( "Post &#8211; Event", 'ccat' );
__( "Post &#8211; Listing", 'ccat' );
__( "Post &#8211; Location", 'ccat' );
__( "Post &#8211; Membership", 'ccat' );
__( "Post &#8211; Page", 'ccat' );
__( "Post &#8211; Profile", 'ccat' );
__( "Post &#8211; Project", 'ccat' );
__( "Post &#8211; Representation", 'ccat' );
__( "Post &#8211; Resource", 'ccat' );
__( "Post &#8211; Template", 'ccat' );
__( "Postponed", 'ccat' );
__( "Pricing", 'ccat' );
__( "Profile type", 'ccat' );
__( "Profile(s)", 'ccat' );
__( "Project categorie(s)", 'ccat' );
__( "Range", 'ccat' );
__( "Rechercher une adresse...", 'ccat' );
__( "Registration", 'ccat' );
__( "Resource category", 'ccat' );
__( "Salle de spectacle", 'ccat' );
__( "Same as contact", 'ccat' );
__( "Schedule type", 'ccat' );
__( "Search for address...", 'ccat' );
__( "Section &#8211; Container", 'ccat' );
__( "Section &#8211; Theme", 'ccat' );
__( "Section(s)", 'ccat' );
__( "Select", 'ccat' );
__( "Sent", 'ccat' );
@@ -122,6 +146,7 @@ __( "Start date / time", 'ccat' );
__( "Start month", 'ccat' );
__( "Subject", 'ccat' );
__( "Target audience", 'ccat' );
__( "Template", 'ccat' );
__( "Term &#8211; Discipline", 'ccat' );
__( "Text block", 'ccat' );
__( "This event is asynchronous", 'ccat' );

View File

@@ -0,0 +1,84 @@
{
"key": "group_abstract_address_city",
"title": "Abstract - Address (city)",
"fields": [
{
"key": "field_68d5527e52ccc",
"label": "Address",
"name": "address",
"aria-label": "",
"type": "acfe_address",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"placeholder": "Rechercher une adresse...",
"countries": [
"ca"
],
"search_type": "(cities)",
"geolocation": 1,
"custom_address": 0,
"prepend": "",
"append": "",
"api_key": "",
"fields": {
"68d553b4318a6": {
"field": "address",
"name": "formatted"
},
"row-row-0": {
"field": "country_short",
"name": "country_code"
},
"row-row-1": {
"field": "state_short",
"name": "state_code"
},
"row-68d552af52ccd": {
"field": "post_code",
"name": "postal_code"
}
},
"required_message": "",
"allow_in_bindings": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "address",
"graphql_non_null": 1,
"default_value": ""
}
],
"location": [
[
{
"param": "abstract"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "top",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "groupAbstractAddressCity",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1758811326
}

View File

@@ -0,0 +1,96 @@
{
"key": "group_abstract_address_contact",
"title": "Abstract - Address (contact)",
"fields": [
{
"key": "field_address_contact_location",
"label": "Address",
"name": "address",
"aria-label": "",
"type": "acfe_address",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"placeholder": "Search for address...",
"countries": [
"ca"
],
"search_type": "address",
"geolocation": 1,
"custom_address": 0,
"prepend": "",
"append": "",
"api_key": "",
"fields": {
"row-4": {
"field": "address",
"name": "formatted"
},
"row-1": {
"field": "country_short",
"name": "country_code"
},
"row-3": {
"field": "state_short",
"name": "state_code"
},
"68d554ddf7c58": {
"field": "city",
"name": "city"
},
"68d554e3f7c59": {
"field": "post_code",
"name": "postal_code"
},
"68d554ecf7c5a": {
"field": "street_number",
"name": "street_number"
},
"68d554f6f7c5b": {
"field": "street_name",
"name": "street_name"
}
},
"required_message": "",
"allow_in_bindings": 1,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "address",
"graphql_non_null": 1,
"default_value": ""
}
],
"location": [
[
{
"param": "abstract"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "top",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "groupAbstractAddressContact",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1758811411
}

View File

@@ -0,0 +1,106 @@
{
"key": "group_abstract_address_geo",
"title": "Abstract - Address (geo)",
"fields": [
{
"key": "field_address_geo_location",
"label": "Address",
"name": "address",
"aria-label": "",
"type": "acfe_address",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"placeholder": "Search for address...",
"countries": "",
"search_type": "establishment",
"geolocation": 1,
"custom_address": 0,
"prepend": "",
"append": "",
"api_key": "",
"fields": {
"row-0": {
"field": "address",
"name": "formatted"
},
"row-1": {
"field": "country_short",
"name": "country_code"
},
"row-2": {
"field": "state_short",
"name": "state_code"
},
"row-3": {
"field": "city",
"name": "city"
},
"row-4": {
"field": "post_code",
"name": "postal_code"
},
"row-5": {
"field": "street_number",
"name": "street_number"
},
"row-6": {
"field": "street_name",
"name": "street_name"
},
"68d55568a379d": {
"field": "place_id",
"name": "place_id"
},
"68d5556da379e": {
"field": "lat",
"name": "lat"
},
"68d55571a379f": {
"field": "lng",
"name": "lng"
}
},
"required_message": "",
"allow_in_bindings": 1,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "address",
"graphql_non_null": 0,
"default_value": ""
}
],
"location": [
[
{
"param": "abstract"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "top",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "groupAbstractAddressGeo",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1758811522
}

View File

@@ -16,6 +16,41 @@
"class": "",
"id": ""
},
"acfe_flexible_advanced": 1,
"acfe_flexible_stylised_button": 0,
"acfe_flexible_hide_empty_message": 0,
"acfe_flexible_empty_message": "",
"acfe_flexible_layouts_templates": 1,
"acfe_flexible_layouts_previews": 1,
"acfe_flexible_layouts_previews_iframe": 1,
"acfe_flexible_layouts_previews_responsive": 1,
"acfe_flexible_layouts_thumbnails": 0,
"acfe_flexible_layouts_settings": 1,
"acfe_flexible_layouts_locations": 0,
"acfe_flexible_async": [],
"acfe_flexible_add_actions": [
"title",
"toggle",
"copy"
],
"acfe_flexible_remove_button": [],
"acfe_flexible_modal_edit": {
"acfe_flexible_modal_edit_enabled": "1",
"acfe_flexible_modal_edit_size": "xlarge"
},
"acfe_flexible_modal": {
"acfe_flexible_modal_enabled": "0",
"acfe_flexible_modal_title": false,
"acfe_flexible_modal_size": "full",
"acfe_flexible_modal_col": "4",
"acfe_flexible_modal_categories": false
},
"acfe_flexible_grid": {
"acfe_flexible_grid_enabled": "0",
"acfe_flexible_grid_align": "center",
"acfe_flexible_grid_valign": "stretch",
"acfe_flexible_grid_wrap": false
},
"layouts": {
"layout_6852f761e95b0": {
"key": "layout_6852f761e95b0",
@@ -38,18 +73,7 @@
"id": ""
},
"default_value": "",
"allow_in_bindings": 0,
"tabs": "all",
"toolbar": "full",
"media_upload": 1,
"delay": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "content",
"graphql_non_null": 0,
"acfe_wysiwyg_auto_init": 0,
"acfe_wysiwyg_height": 300,
"acfe_wysiwyg_min_height": 300,
"acfe_wysiwyg_max_height": "",
"acfe_wysiwyg_valid_elements": "",
"acfe_wysiwyg_custom_style": "",
@@ -61,11 +85,99 @@
"acfe_wysiwyg_transparent": 0,
"acfe_wysiwyg_merge_toolbar": 0,
"acfe_wysiwyg_custom_toolbar": 0,
"required_message": "",
"allow_in_bindings": 0,
"tabs": "all",
"toolbar": "full",
"media_upload": 1,
"delay": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "content",
"graphql_non_null": 1,
"acfe_wysiwyg_auto_init": 0,
"acfe_wysiwyg_min_height": 300,
"acfe_wysiwyg_toolbar_buttons": []
}
],
"min": "",
"max": ""
"max": "",
"acfe_flexible_render_template": "",
"acfe_flexible_render_style": "",
"acfe_flexible_render_script": "",
"acfe_flexible_modal_edit_size": "",
"acfe_flexible_settings": [
"group_section_container",
"group_section_theme"
],
"acfe_flexible_settings_size": "large",
"acfe_flexible_thumbnail": false,
"acfe_layout_locations": [],
"acfe_flexible_category": false,
"acfe_layout_col": "auto",
"acfe_layout_allowed_col": false
},
"layout_68d559a93813a": {
"key": "layout_68d559a93813a",
"name": "template",
"label": "Template",
"display": "block",
"sub_fields": [
{
"key": "field_template_id",
"label": "Template",
"name": "template",
"aria-label": "",
"type": "post_object",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"post_type": [
"template"
],
"post_status": "",
"taxonomy": "",
"return_format": "id",
"multiple": 0,
"max": "",
"save_custom": 0,
"save_post_status": "publish",
"acfe_add_post": 0,
"acfe_edit_post": 0,
"acfe_bidirectional": {
"acfe_bidirectional_enabled": "0"
},
"allow_null": 0,
"allow_in_bindings": 0,
"bidirectional": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "template",
"graphql_connection_type": "one_to_many",
"ui": 1,
"bidirectional_target": [],
"save_post_type": "",
"min": ""
}
],
"min": "",
"max": "",
"acfe_flexible_render_template": "",
"acfe_flexible_render_style": "",
"acfe_flexible_render_script": "",
"acfe_flexible_modal_edit_size": "",
"acfe_flexible_settings": "",
"acfe_flexible_settings_size": "large",
"acfe_flexible_thumbnail": false,
"acfe_layout_locations": [],
"acfe_flexible_category": false,
"acfe_layout_col": "auto",
"acfe_layout_allowed_col": false
}
},
"min": "",
@@ -74,7 +186,10 @@
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "sections",
"graphql_non_null": 0
"graphql_non_null": 0,
"acfe_flexible_layouts_placeholder": false,
"acfe_flexible_layouts_state": false,
"acfe_flexible_grid_container": false
}
],
"location": [
@@ -95,9 +210,16 @@
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "abstractBuilder",
"graphql_field_name": "groupAbstractBuilder",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"modified": 1750345147
"acfe_meta": "",
"acfe_note": "",
"modified": 1758814061
}

View File

@@ -0,0 +1,174 @@
{
"key": "group_abstract_contact",
"title": "Abstract - Contact",
"fields": [
{
"key": "field_contact_first_name",
"label": "First name",
"name": "first_name",
"aria-label": "",
"type": "text",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "50",
"class": "",
"id": ""
},
"default_value": "",
"required_message": "",
"maxlength": "",
"allow_in_bindings": 0,
"placeholder": "",
"prepend": "",
"append": "",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "firstName",
"graphql_non_null": 1
},
{
"key": "field_contact_last_name",
"label": "Last name",
"name": "last_name",
"aria-label": "",
"type": "text",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "50",
"class": "",
"id": ""
},
"default_value": "",
"required_message": "",
"maxlength": "",
"allow_in_bindings": 0,
"placeholder": "",
"prepend": "",
"append": "",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "lastName",
"graphql_non_null": 1
},
{
"key": "field_contact_email",
"label": "Email",
"name": "email",
"aria-label": "",
"type": "email",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "50",
"class": "",
"id": ""
},
"default_value": "",
"required_message": "",
"allow_in_bindings": 0,
"placeholder": "",
"prepend": "",
"append": "",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "email",
"graphql_non_null": 1
},
{
"key": "field_contact_phone",
"label": "Phone",
"name": "phone",
"aria-label": "",
"type": "acfe_phone_number",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "50",
"class": "",
"id": ""
},
"countries": [
"ca"
],
"preferred_countries": "",
"default_country": "ca",
"geolocation": 0,
"native": 0,
"national": 0,
"dropdown": 0,
"dial_code": 0,
"default_value": "",
"placeholder": "",
"return_format": "array",
"required_message": "",
"allow_in_bindings": 1,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "phone",
"graphql_non_null": 1,
"geolocation_token": ""
},
{
"key": "field_contact_address",
"label": "Address",
"name": "address",
"aria-label": "",
"type": "clone",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"graphql_field_name": "address",
"clone": [
"field_address_contact_location"
],
"display": "seamless",
"layout": "block",
"prefix_label": 0,
"prefix_name": 0,
"acfe_seamless_style": 0,
"acfe_clone_modal": 0,
"acfe_clone_modal_close": 0,
"acfe_clone_modal_button": "",
"acfe_clone_modal_size": "large"
}
],
"location": [
[
{
"param": "abstract"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "top",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "groupAbstractContact",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1758811604
}

View File

@@ -132,10 +132,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "abstractCredits",
"graphql_field_name": "groupAbstractCredits",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750771257
"modified": 1757960600
}

View File

@@ -27,6 +27,7 @@
"graphql_field_name": "identifiers",
"graphql_non_null": 0,
"rows_per_page": 20,
"acfe_repeater_stylised_button": 0,
"sub_fields": [
{
"key": "field_685413ff154d0",
@@ -70,9 +71,16 @@
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "abstractEntity",
"graphql_field_name": "groupAbstractEntity",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"modified": 1750344613
"acfe_meta": "",
"acfe_note": "",
"modified": 1757960593
}

View File

@@ -169,10 +169,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "abstractGallery",
"graphql_field_name": "groupAbstractGallery",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750771280
"modified": 1757960586
}

View File

@@ -667,10 +667,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "abstractOffer",
"graphql_field_name": "groupAbstractOffer",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1754494059
"modified": 1757960580
}

View File

@@ -77,10 +77,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "abstractSocial",
"graphql_field_name": "groupAbstractSocial",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1756232042
"modified": 1757960554
}

View File

@@ -55,10 +55,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "ccat",
"graphql_field_name": "groupCcat",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1756231316
"modified": 1757960547
}

View File

@@ -57,10 +57,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postArticle",
"graphql_field_name": "groupPostArticle",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750444933
"modified": 1757960479
}

View File

@@ -139,8 +139,8 @@
},
{
"key": "field_685aa158687d2",
"label": "Locality",
"name": "locality",
"label": "Localities",
"name": "localities",
"aria-label": "",
"type": "repeater",
"instructions": "",
@@ -160,7 +160,7 @@
"button_label": "Ajouter un élément",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "locality",
"graphql_field_name": "localities",
"graphql_non_null": 0,
"rows_per_page": 20,
"sub_fields": [
@@ -169,9 +169,9 @@
"label": "Address",
"name": "address",
"aria-label": "",
"type": "acfe_address",
"type": "clone",
"instructions": "",
"required": 0,
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
@@ -179,30 +179,18 @@
"id": ""
},
"graphql_field_name": "address",
"placeholder": "Rechercher une adresse...",
"countries": "",
"search_type": "(cities)",
"geolocation": 1,
"custom_address": 0,
"prepend": "",
"append": "",
"api_key": "",
"fields": {
"row-2": {
"field": "country_short",
"name": "country"
},
"row-1": {
"field": "state",
"name": "state"
},
"685aa185687d4": {
"field": "city",
"name": "city"
}
},
"allow_in_bindings": 0,
"default_value": "",
"clone": [
"field_68d5527e52ccc"
],
"display": "seamless",
"layout": "block",
"prefix_label": 0,
"prefix_name": 0,
"acfe_seamless_style": 0,
"acfe_clone_modal": 0,
"acfe_clone_modal_close": 0,
"acfe_clone_modal_button": "",
"acfe_clone_modal_size": "large",
"parent_repeater": "field_685aa158687d2"
}
]
@@ -350,10 +338,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postContributor",
"graphql_field_name": "groupPostContributor",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1751980995
"modified": 1758822397
}

View File

@@ -366,10 +366,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postEvent",
"graphql_field_name": "groupPostEvent",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750769168
"modified": 1757960457
}

View File

@@ -0,0 +1,107 @@
{
"key": "group_post_listing",
"title": "Post - Listing",
"fields": [
{
"key": "field_listing_category",
"label": "Listing category",
"name": "listing_category",
"aria-label": "",
"type": "taxonomy",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"taxonomy": "listing_category",
"field_type": "select",
"allow_null": 0,
"add_term": 0,
"save_terms": 1,
"load_terms": 1,
"return_format": "object",
"multiple": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "listingCategory",
"graphql_non_null": 1
},
{
"key": "field_listing_deadline",
"label": "Application deadline",
"name": "deadline",
"aria-label": "",
"type": "date_picker",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "50",
"class": "",
"id": ""
},
"display_format": "Y-m-d",
"return_format": "Y-m-d",
"first_day": 1,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "deadline",
"graphql_non_null": 0
},
{
"key": "field_listing_external_link",
"label": "External link",
"name": "external_link",
"aria-label": "",
"type": "url",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "50",
"class": "",
"id": ""
},
"default_value": "",
"allow_in_bindings": 0,
"placeholder": "",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "externalLink",
"graphql_non_null": 0
}
],
"location": [
[
{
"param": "post_type",
"operator": "==",
"value": "listing"
}
]
],
"menu_order": 0,
"position": "acf_after_title",
"style": "seamless",
"label_placement": "left",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postListing",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1758744226
}

View File

@@ -87,9 +87,9 @@
"label": "Address",
"name": "address",
"aria-label": "",
"type": "acfe_address",
"type": "clone",
"instructions": "",
"required": 1,
"required": 0,
"conditional_logic": [
[
{
@@ -105,44 +105,18 @@
"id": ""
},
"graphql_field_name": "address",
"placeholder": "Search for address...",
"countries": [
"ca"
"clone": [
"field_address_geo_location"
],
"search_type": "establishment",
"geolocation": 0,
"custom_address": 1,
"prepend": "",
"append": "",
"api_key": "",
"fields": {
"row-0": {
"field": "address",
"name": "full"
},
"row-1": {
"field": "city",
"name": "city"
},
"row-2": {
"field": "post_code",
"name": "postal_code"
},
"6855af79da244": {
"field": "place_id",
"name": "place_id"
},
"6855b005da245": {
"field": "lat",
"name": "lat"
},
"6855b009da246": {
"field": "lng",
"name": "lng"
}
},
"allow_in_bindings": 0,
"default_value": ""
"display": "group",
"layout": "block",
"prefix_label": 0,
"prefix_name": 0,
"acfe_seamless_style": 0,
"acfe_clone_modal": 0,
"acfe_clone_modal_close": 0,
"acfe_clone_modal_button": "",
"acfe_clone_modal_size": "large"
},
{
"key": "field_6855b0c3c5a81",
@@ -347,10 +321,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postLocation",
"graphql_field_name": "groupPostLocation",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1751981084
"modified": 1758812298
}

View File

@@ -1,350 +0,0 @@
{
"key": "group_post_membership",
"title": "Post - Membership",
"fields": [
{
"key": "field_6855b1f1c65bf",
"label": "Membership plan",
"name": "membership_plan",
"aria-label": "",
"type": "select",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"Membre (individu)": "Membre (individu)",
"Membre (organisation)": "Membre (organisation)"
},
"default_value": false,
"return_format": "value",
"multiple": 0,
"max": "",
"prepend": "",
"append": "",
"required_message": "",
"allow_null": 0,
"allow_in_bindings": 0,
"ui": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "membershipPlan",
"graphql_non_null": 1,
"ajax": 0,
"placeholder": "",
"create_options": 0,
"save_options": 0,
"allow_custom": 0,
"search_placeholder": "",
"min": ""
},
{
"key": "field_6855ab54c65bc",
"label": "Managed contributor",
"name": "contributor",
"aria-label": "",
"type": "post_object",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"post_type": [
"contributor"
],
"post_status": "",
"taxonomy": "",
"return_format": "id",
"multiple": 0,
"save_custom": 0,
"save_post_status": "publish",
"acfe_add_post": 0,
"acfe_edit_post": 0,
"acfe_bidirectional": {
"acfe_bidirectional_enabled": "0"
},
"allow_null": 0,
"allow_in_bindings": 0,
"bidirectional": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "contributor",
"graphql_connection_type": "one_to_many",
"ui": 1,
"bidirectional_target": [],
"save_post_type": "",
"min": "",
"max": ""
},
{
"key": "field_686d1fab5de85",
"label": "Billing",
"name": "billing",
"aria-label": "",
"type": "group",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "block",
"acfe_seamless_style": 0,
"acfe_group_modal": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "payment",
"graphql_non_null": 0,
"sub_fields": [
{
"key": "field_686d20578e1b5",
"label": "Person name",
"name": "person_name",
"aria-label": "",
"type": "text",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"required_message": "",
"maxlength": "",
"allow_in_bindings": 0,
"placeholder": "",
"prepend": "",
"append": "",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "personName",
"graphql_non_null": 1
},
{
"key": "field_686d208c8e1b6",
"label": "Email",
"name": "email",
"aria-label": "",
"type": "email",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"allow_in_bindings": 0,
"placeholder": "",
"prepend": "",
"append": "",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "email",
"graphql_non_null": 1
},
{
"key": "field_686d20a08e1b7",
"label": "Phone",
"name": "phone",
"aria-label": "",
"type": "acfe_phone_number",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"countries": [
"ca"
],
"preferred_countries": "",
"default_country": "ca",
"geolocation": 0,
"native": 0,
"national": 1,
"dropdown": 0,
"dial_code": 0,
"default_value": "",
"placeholder": "",
"return_format": "number",
"allow_in_bindings": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "phone",
"graphql_non_null": 1,
"geolocation_token": ""
},
{
"key": "field_686d20d48e1b8",
"label": "Address",
"name": "address",
"aria-label": "",
"type": "acfe_address",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"graphql_field_name": "address",
"placeholder": "Rechercher une adresse...",
"countries": [
"ca"
],
"search_type": "address",
"geolocation": 1,
"custom_address": 1,
"prepend": "",
"append": "",
"api_key": "",
"fields": {
"row-0": {
"field": "street_number",
"name": "street_number"
},
"686d21068e1b9": {
"field": "street_number",
"name": "street_name"
},
"686d210f8e1ba": {
"field": "city",
"name": "city"
},
"row-1": {
"field": "state",
"name": "state"
},
"row-2": {
"field": "country_short",
"name": "country"
},
"686d21198e1bb": {
"field": "post_code",
"name": "post_code"
}
},
"allow_in_bindings": 0,
"default_value": ""
}
],
"acfe_group_modal_close": 0,
"acfe_group_modal_button": "",
"acfe_group_modal_size": "large"
},
{
"key": "field_686d1ffa5de87",
"label": "Individual profile",
"name": "individual_profile",
"aria-label": "",
"type": "group",
"instructions": "",
"required": 0,
"conditional_logic": [
[
{
"field": "field_6855b1f1c65bf",
"operator": "==",
"value": "Membre (individu)"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "block",
"acfe_seamless_style": 0,
"acfe_group_modal": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "individualProfile",
"graphql_non_null": 0,
"sub_fields": [],
"acfe_group_modal_close": 0,
"acfe_group_modal_button": "",
"acfe_group_modal_size": "large"
},
{
"key": "field_686d20215de88",
"label": "Organization profile",
"name": "organization_profile",
"aria-label": "",
"type": "group",
"instructions": "",
"required": 0,
"conditional_logic": [
[
{
"field": "field_6855b1f1c65bf",
"operator": "==",
"value": "Membre (organisation)"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "block",
"acfe_seamless_style": 0,
"acfe_group_modal": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "organizationProfile",
"graphql_non_null": 0,
"sub_fields": [],
"acfe_group_modal_close": 0,
"acfe_group_modal_button": "",
"acfe_group_modal_size": "large"
}
],
"location": [
[
{
"param": "post_type",
"operator": "==",
"value": "membership"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "seamless",
"label_placement": "top",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postMembership",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1751982478
}

View File

@@ -57,10 +57,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postPage",
"graphql_field_name": "groupPostPage",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750446725
"modified": 1758829149
}

View File

@@ -0,0 +1,315 @@
{
"key": "group_post_profile",
"title": "Post - Profile",
"fields": [
{
"key": "field_68c85464c2413",
"label": "Contact",
"name": "contact",
"aria-label": "",
"type": "clone",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"graphql_field_name": "contact",
"clone": [
"group_abstract_contact"
],
"display": "seamless",
"layout": "block",
"prefix_label": 0,
"prefix_name": 0,
"acfe_seamless_style": 0,
"acfe_clone_modal": 0,
"acfe_clone_modal_close": 0,
"acfe_clone_modal_button": "",
"acfe_clone_modal_size": "large"
},
{
"key": "field_68c85488c241d",
"label": "Same as contact",
"name": "billing_same",
"aria-label": "",
"type": "true_false",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"message": "Billing is the same as contact",
"default_value": 0,
"allow_in_bindings": 0,
"ui": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "sameAsContact",
"graphql_non_null": 0,
"ui_on_text": "",
"ui_off_text": "",
"style": ""
},
{
"key": "field_686d1fab5de85",
"label": "Billing",
"name": "billing",
"aria-label": "",
"type": "clone",
"instructions": "",
"required": 0,
"conditional_logic": [
[
{
"field": "field_68c85488c241d",
"operator": "!=",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"graphql_field_name": "billing",
"clone": [
"group_abstract_contact"
],
"display": "group",
"layout": "block",
"prefix_label": 0,
"prefix_name": 0,
"acfe_seamless_style": 0,
"acfe_clone_modal": 0,
"acfe_clone_modal_close": 0,
"acfe_clone_modal_button": "",
"acfe_clone_modal_size": "large"
},
{
"key": "field_6855b1f1c65bf",
"label": "Profile type",
"name": "profile_type",
"aria-label": "",
"type": "select",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"individual": "Individu",
"collective": "Collectif artistique",
"organization": "Organisation",
"institution": "Institution"
},
"default_value": false,
"return_format": "value",
"multiple": 0,
"max": "",
"prepend": "",
"append": "",
"required_message": "",
"allow_null": 0,
"allow_in_bindings": 0,
"ui": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "profileType",
"graphql_non_null": 1,
"ajax": 0,
"placeholder": "",
"create_options": 0,
"save_options": 0,
"allow_custom": 0,
"search_placeholder": "",
"min": ""
},
{
"key": "field_68c854de2bef8",
"label": "Email preferences",
"name": "email_preferences",
"aria-label": "",
"type": "group",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "block",
"acfe_seamless_style": 0,
"acfe_group_modal": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "emailPreferences",
"graphql_non_null": 1,
"acfe_group_modal_close": 0,
"acfe_group_modal_button": "",
"acfe_group_modal_size": "large",
"sub_fields": [
{
"key": "field_686d2332cf01e",
"label": "Categorie(s)",
"name": "categories",
"aria-label": "",
"type": "checkbox",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": [],
"default_value": [],
"return_format": "value",
"min": "",
"max": "",
"allow_custom": 0,
"allow_in_bindings": 0,
"layout": "vertical",
"toggle": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "categories",
"graphql_non_null": 0,
"save_custom": 0,
"custom_choice_button_text": "Add new choice"
},
{
"key": "field_686d230dcf01c",
"label": "Discipline(s)",
"name": "disciplines",
"aria-label": "",
"type": "checkbox",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": [],
"default_value": [],
"return_format": "value",
"min": "",
"max": "",
"allow_custom": 0,
"allow_in_bindings": 0,
"layout": "vertical",
"toggle": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "disciplines",
"graphql_non_null": 0,
"save_custom": 0,
"custom_choice_button_text": "Add new choice"
},
{
"key": "field_686d22b4cf01b",
"label": "Event type(s)",
"name": "event_types",
"aria-label": "",
"type": "checkbox",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"graphql_field_name": "eventTypes",
"choices": [],
"default_value": [],
"return_format": "value",
"min": "",
"max": "",
"allow_custom": 0,
"allow_in_bindings": 0,
"layout": "vertical",
"toggle": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_non_null": 0,
"save_custom": 0,
"custom_choice_button_text": "Add new choice"
},
{
"key": "field_686d2323cf01d",
"label": "MRC",
"name": "mrc",
"aria-label": "",
"type": "checkbox",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": [],
"default_value": [],
"return_format": "value",
"min": "",
"max": "",
"allow_custom": 0,
"allow_in_bindings": 0,
"layout": "vertical",
"toggle": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "mrc",
"graphql_non_null": 0,
"save_custom": 0,
"custom_choice_button_text": "Add new choice"
}
]
}
],
"location": [
[
{
"param": "post_type",
"operator": "==",
"value": "profile"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "seamless",
"label_placement": "top",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "groupPostProfile",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1758812459
}

View File

@@ -4,7 +4,7 @@
"fields": [
{
"key": "field_685413d901253",
"label": "Categorie(s)",
"label": "Project categorie(s)",
"name": "project_categories",
"aria-label": "",
"type": "taxonomy",
@@ -171,10 +171,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postProject",
"graphql_field_name": "groupPostProject",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750769378
"modified": 1757959216
}

View File

@@ -255,7 +255,7 @@
{
"key": "field_6855b5083f269",
"label": "Start date \/ time",
"name": "start_date__time",
"name": "start_date_time",
"aria-label": "",
"type": "date_time_picker",
"instructions": "",
@@ -281,6 +281,7 @@
"max_min": "",
"min_sec": "",
"max_sec": "",
"required_message": "",
"allow_in_bindings": 0,
"show_in_graphql": 1,
"graphql_description": "",
@@ -375,10 +376,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postRepresentation",
"graphql_field_name": "groupPostRepresentation",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1751982621
"modified": 1757959184
}

View File

@@ -4,7 +4,7 @@
"fields": [
{
"key": "field_685413ded6377",
"label": "Category",
"label": "Resource category",
"name": "resource_category",
"aria-label": "",
"type": "taxonomy",
@@ -60,7 +60,7 @@
"button_label": "Ajouter un élément",
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "resourceItems",
"graphql_field_name": "documents",
"graphql_non_null": 0,
"rows_per_page": 20,
"sub_fields": [
@@ -234,10 +234,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postResource",
"graphql_field_name": "groupPostResource",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750769553
"modified": 1757959119
}

View File

@@ -55,10 +55,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "postTemplate",
"graphql_field_name": "groupPostTemplate",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750447786
"modified": 1757959017
}

View File

@@ -0,0 +1,79 @@
{
"key": "group_section_container",
"title": "Section - Container",
"fields": [
{
"key": "field_68d18dd881229",
"label": "Content width",
"name": "content_width",
"aria-label": "",
"type": "select",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"container": "Default container",
"container-fluid": "Fluid container",
"container-full": "Full-width container",
"container-sm": "640px container",
"container-md": "768px container",
"container-lg": "1024px container",
"container-xl": "1280px container"
},
"default_value": "container",
"return_format": "value",
"multiple": 0,
"max": "",
"prepend": "",
"append": "",
"required_message": "",
"allow_null": 0,
"allow_in_bindings": 0,
"ui": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "contentWidth",
"graphql_non_null": 0,
"ajax": 0,
"placeholder": "",
"create_options": 0,
"save_options": 0,
"allow_custom": 0,
"search_placeholder": "",
"min": ""
}
],
"location": [
[
{
"param": "abstract"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "left",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "sectionContainer",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1758742387
}

View File

@@ -0,0 +1,76 @@
{
"key": "group_section_theme",
"title": "Section - Theme",
"fields": [
{
"key": "field_68d190c22372a",
"label": "Background color",
"name": "bg_color",
"aria-label": "",
"type": "select",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"bg-default": "Default background",
"bg-muted": "Muted background",
"bg-elevated": "Elevated background",
"bg-accented": "Accented background"
},
"default_value": "bg-default",
"return_format": "value",
"multiple": 0,
"max": "",
"prepend": "",
"append": "",
"required_message": "",
"allow_null": 0,
"allow_in_bindings": 0,
"ui": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "bgColor",
"graphql_non_null": 0,
"ajax": 0,
"placeholder": "",
"create_options": 0,
"save_options": 0,
"allow_custom": 0,
"search_placeholder": "",
"min": ""
}
],
"location": [
[
{
"param": "abstract"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "left",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "",
"show_in_rest": 0,
"acfe_autosync": [
"json"
],
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "sectionTheme",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1758742399
}

View File

@@ -55,10 +55,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "termDiscipline",
"graphql_field_name": "groupTermDiscipline",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1750447831
"modified": 1757959003
}

View File

@@ -42,153 +42,6 @@
"ui": 1,
"bidirectional_target": [],
"save_post_type": ""
},
{
"key": "field_686d2299cf01a",
"label": "Email preferences",
"name": "email_preferences",
"aria-label": "",
"type": "group",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "block",
"acfe_seamless_style": 1,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "emailPreferences",
"graphql_non_null": 0,
"sub_fields": [
{
"key": "field_686d2332cf01e",
"label": "Categorie(s)",
"name": "categories",
"aria-label": "",
"type": "checkbox",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": [],
"default_value": [],
"return_format": "value",
"min": "",
"max": "",
"allow_custom": 0,
"allow_in_bindings": 0,
"layout": "vertical",
"toggle": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "categories",
"graphql_non_null": 0,
"save_custom": 0,
"custom_choice_button_text": "Add new choice"
},
{
"key": "field_686d230dcf01c",
"label": "Discipline(s)",
"name": "disciplines",
"aria-label": "",
"type": "checkbox",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": [],
"default_value": [],
"return_format": "value",
"min": "",
"max": "",
"allow_custom": 0,
"allow_in_bindings": 0,
"layout": "vertical",
"toggle": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "disciplines",
"graphql_non_null": 0,
"save_custom": 0,
"custom_choice_button_text": "Add new choice"
},
{
"key": "field_686d22b4cf01b",
"label": "Event type(s)",
"name": "event_types",
"aria-label": "",
"type": "checkbox",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"graphql_field_name": "eventTypes",
"choices": [],
"default_value": [],
"return_format": "value",
"min": "",
"max": "",
"allow_custom": 0,
"allow_in_bindings": 0,
"layout": "vertical",
"toggle": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_non_null": 0,
"save_custom": 0,
"custom_choice_button_text": "Add new choice"
},
{
"key": "field_686d2323cf01d",
"label": "MRC",
"name": "mrc",
"aria-label": "",
"type": "checkbox",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": [],
"default_value": [],
"return_format": "value",
"min": "",
"max": "",
"allow_custom": 0,
"allow_in_bindings": 0,
"layout": "vertical",
"toggle": 0,
"show_in_graphql": 1,
"graphql_description": "",
"graphql_field_name": "mrc",
"graphql_non_null": 0,
"save_custom": 0,
"custom_choice_button_text": "Add new choice"
}
],
"acfe_group_modal": 0,
"acfe_group_modal_close": 0,
"acfe_group_modal_button": "",
"acfe_group_modal_size": "large"
}
],
"location": [
@@ -215,10 +68,10 @@
"acfe_form": 0,
"acfe_display_title": "",
"show_in_graphql": 1,
"graphql_field_name": "userProfile",
"graphql_field_name": "groupUserProfile",
"map_graphql_types_from_location_rules": 0,
"graphql_types": "",
"acfe_meta": "",
"acfe_note": "",
"modified": 1751982984
"modified": 1757958987
}

View File

@@ -0,0 +1,10 @@
import { defineAppConfig } from "#imports";
export default defineAppConfig({
ui: {
colors: {
primary: "indigo",
neutral: "neutral",
},
},
});

View File

@@ -0,0 +1,30 @@
<script setup lang="ts">
import { fr } from "@nuxt/ui/locale";
useHead({
htmlAttrs: {
lang: "fr-CA",
},
meta: [
{ charset: "utf-8" },
{ name: "viewport", content: "width=device-width, initial-scale=1" },
],
link: [
{ rel: "icon", href: "/favicon.ico" },
],
});
useSeoMeta({
titleTemplate: "%s - Conseil de la culture de l'Abitibi-Témiscamingue",
});
</script>
<template>
<UApp :locale="fr">
<NuxtRouteAnnouncer />
<NuxtLoadingIndicator />
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</UApp>
</template>

View File

@@ -0,0 +1,23 @@
@layer components {
.container {
@apply mx-auto;
}
.container-fluid {
@apply w-full max-w-screen px-4 sm:px-6 lg:px-8;
}
.container-full {
@apply w-full max-w-screen;
}
.container-sm {
@apply container max-w-screen-sm mx-auto;
}
.container-md {
@apply container max-w-screen-md mx-auto;
}
.container-lg {
@apply container max-w-screen-lg mx-auto;
}
.container-xl {
@apply container max-w-screen-xl mx-auto;
}
}

View File

@@ -0,0 +1,6 @@
@layer components {
.flex-break-words {
@apply min-w-0 break-words;
}
}

View File

@@ -0,0 +1,10 @@
@import "tailwindcss";
@import "@nuxt/ui";
@import "./containers.css";
@import "./helpers.css";
@source "../../../acf-json";
@theme {
--z-index-main: 10;
}

View File

@@ -0,0 +1,170 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="4.04in" height="1.52in" viewBox="0 0 290.92 109.68">
<defs>
<style>
.cls-1 {
fill: url(#linear-gradient);
}
.cls-2 {
fill: url(#linear-gradient-2);
}
.cls-3 {
fill: url(#linear-gradient-3);
}
.cls-4 {
fill: url(#linear-gradient-4);
}
.cls-5 {
fill: url(#linear-gradient-5);
}
.cls-6 {
fill: url(#linear-gradient-6);
}
.cls-7 {
fill: url(#linear-gradient-7);
}
.cls-8 {
fill: url(#linear-gradient-8);
}
.cls-9 {
fill: url(#linear-gradient-12);
}
.cls-10 {
fill: url(#linear-gradient-15);
}
.cls-11 {
fill: url(#linear-gradient-16);
}
.cls-12 {
fill: url(#linear-gradient-22);
}
.cls-13 {
fill: url(#linear-gradient-25);
}
.cls-14 {
fill: url(#linear-gradient-26);
}
.cls-15 {
fill: url(#linear-gradient-33);
}
.cls-16 {
fill: url(#linear-gradient-35);
}
.cls-17 {
fill: url(#linear-gradient-45);
}
.cls-18 {
fill: url(#linear-gradient-47);
}
.cls-19 {
fill: url(#linear-gradient-49);
}
.cls-20 {
fill: url(#linear-gradient-50);
}
</style>
<linearGradient id="linear-gradient" x1="-19.84" y1="71.96" x2="296.65" y2="71.96" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#cf8837"/>
<stop offset="0.41" stop-color="#bd4931"/>
<stop offset="1" stop-color="#2e3191"/>
</linearGradient>
<linearGradient id="linear-gradient-2" x1="-19.84" y1="32.09" x2="296.65" y2="32.09" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-3" x1="-19.84" y1="27.58" x2="296.65" y2="27.58" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-4" x1="-19.84" y1="20.21" x2="296.65" y2="20.21" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-5" x1="-19.84" y1="12.87" x2="296.65" y2="12.87" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-6" x1="-19.84" y1="12.38" x2="296.65" y2="12.38" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-7" x1="-19.84" y1="48.34" x2="296.65" y2="48.34" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-8" x1="-19.84" y1="31.96" x2="296.65" y2="31.96" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-12" x1="-19.84" y1="31.96" x2="296.65" y2="31.96" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-15" x1="-19.84" y1="71.7" x2="296.65" y2="71.7" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-16" x1="-19.84" y1="71.92" x2="296.65" y2="71.92" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-22" x1="-19.84" y1="103.92" x2="296.65" y2="103.92" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-25" x1="-19.84" y1="100.47" x2="296.65" y2="100.47" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-26" x1="-19.84" y1="103.85" x2="296.65" y2="103.85" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-33" x1="-19.84" y1="104.11" x2="296.65" y2="104.11" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-35" x1="-19.84" y1="102.27" x2="296.65" y2="102.27" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-45" x1="-19.84" y1="104" x2="296.65" y2="104" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-47" x1="-19.84" y1="63.12" x2="296.65" y2="63.12" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-49" x1="-19.84" y1="80.6" x2="296.65" y2="80.6" xlink:href="#linear-gradient"/>
<linearGradient id="linear-gradient-50" x1="-19.84" y1="80.51" x2="296.65" y2="80.51" xlink:href="#linear-gradient"/>
</defs>
<g>
<path class="cls-1" d="M49.39,34.25a1.09,1.09,0,0,0-1.09,1.09v.79a22.3,22.3,0,0,1-6.1,15.35L36,58.07V44.3a1.1,1.1,0,0,0-2.19,0V74.93l-.5-.32A22.26,22.26,0,0,1,22.94,55.74v-10a1.1,1.1,0,1,0-2.19,0v10A24.43,24.43,0,0,0,32.12,76.45l1.68,1.07v31.07a1.1,1.1,0,0,0,2.19,0V61.26L43.79,53a24.44,24.44,0,0,0,6.7-16.85v-.79A1.09,1.09,0,0,0,49.39,34.25Z"/>
<path class="cls-2" d="M22.41,41.52S20,31.13,15.85,26.94,0,22.63,0,22.63s1.53,8.89,6.3,14.11c4,4.4,12.28,4.8,15.12,4.8C22.05,41.54,22.41,41.52,22.41,41.52ZM7.1,36C3.69,32.26,2,26.4,1.36,23.78c3.14.18,10.75.91,13.71,3.93S20.2,37.56,21,40.44C18.17,40.4,10.67,39.91,7.1,36Z"/>
<path class="cls-3" d="M59.91,30c-2.12-1.29-5.25-.86-7-.44,1.67-.56,4.42-1.63,5.78-3,2-2.1,2-7.95,2-7.95s-4.4.88-7,3.32-2.23,7.61-2.21,8h0v0h0c.22.37,2.74,4.68,5.2,6.06s8.25-.13,8.25-.13S62.94,31.81,59.91,30Zm-5.47-7.31A13.21,13.21,0,0,1,59.49,20c-.14,2.08-.62,4.71-1.62,5.74s-3.6,2.17-5.32,2.75C52.62,26.65,53,24,54.44,22.65Z"/>
<path class="cls-4" d="M44.36,20.52C44.54,12.42,34.8,0,34.8,0s-8.65,9.47-9.18,19.2c-.55,10.1,9.3,21.22,9.3,21.22S44.17,28.94,44.36,20.52Z"/>
<path class="cls-5" d="M20,19s.41-5.24-.89-7.82-6.78-4.4-6.78-4.4-.61,4.39.83,7.56S20,19,20,19ZM13.32,8.3c1.89.8,4.19,2.09,4.83,3.35.71,1.43.85,4,.83,5.83-1.67-.65-4-1.89-4.81-3.62A13,13,0,0,1,13.32,8.3Z"/>
<path class="cls-6" d="M53.17,12.38a2,2,0,1,0-2,2A2,2,0,0,0,53.17,12.38Zm-2,.89a.89.89,0,1,1,.89-.89A.89.89,0,0,1,51.19,13.27Z"/>
<path class="cls-7" d="M10.25,47.25a1.55,1.55,0,1,0,2.19,0A1.55,1.55,0,0,0,10.25,47.25Z"/>
<g>
<g>
<path class="cls-8" d="M88.15,17.82a13.85,13.85,0,0,1,9.5,3.65.77.77,0,0,1,0,1.1l-1.06,1.06c-.32.4-.63.36-1,0a11.93,11.93,0,0,0-7.5-2.94,11.29,11.29,0,0,0,0,22.58c3.41,0,5.42-1.38,7.5-2.95a.75.75,0,0,1,.94-.12l1.18,1.06a.76.76,0,0,1,0,1.06,13.45,13.45,0,0,1-9.54,3.81,14.14,14.14,0,1,1,0-28.27Z"/>
<path class="cls-8" d="M115.71,17.82A14.14,14.14,0,1,1,101.61,32,14.12,14.12,0,0,1,115.71,17.82Zm0,25.52A11.39,11.39,0,1,0,104.36,32,11.41,11.41,0,0,0,115.71,43.34Z"/>
<path class="cls-8" d="M135.85,18.53a.75.75,0,0,1,.75-.71h1l17.71,22.07h.08V19a.74.74,0,0,1,.74-.74h1.38a.77.77,0,0,1,.74.74V45.38a.73.73,0,0,1-.74.71h-.71l-18-22.5h0V45a.74.74,0,0,1-.75.75H136.6a.78.78,0,0,1-.75-.75Z"/>
<path class="cls-8" d="M164.48,41.58c.19-.24.39-.51.59-.75.39-.51.82-.82,1.37-.35.27.23,3.14,3,6.64,3,3.18,0,5.26-2,5.26-4.32,0-2.71-2.36-4.32-6.87-6.2-4.32-1.89-6.91-3.65-6.91-8.13,0-2.67,2.12-7,8.36-7a12.78,12.78,0,0,1,6.71,2,.86.86,0,0,1,.24,1.33c-.16.24-.32.51-.47.75a.9.9,0,0,1-1.38.35,10.93,10.93,0,0,0-5.14-1.81c-4.16,0-5.42,2.67-5.42,4.32,0,2.63,2,4.16,5.3,5.54,5.3,2.16,8.72,4.16,8.72,8.72,0,4.08-3.89,7.06-8.48,7.06a12.81,12.81,0,0,1-8.29-3.18A.86.86,0,0,1,164.48,41.58Z"/>
<path class="cls-9" d="M187.17,19a.74.74,0,0,1,.75-.74h15.47a.74.74,0,0,1,.74.74V20.1a.75.75,0,0,1-.74.75h-13.2v9.58h11.27a.77.77,0,0,1,.75.74v1.14a.75.75,0,0,1-.75.75H190.19v10h13.2a.74.74,0,0,1,.74.74V45a.74.74,0,0,1-.74.75H187.92a.74.74,0,0,1-.75-.75Z"/>
<path class="cls-9" d="M210.42,19a.77.77,0,0,1,.74-.74h1.57a.77.77,0,0,1,.75.74V45a.77.77,0,0,1-.75.75h-1.57a.77.77,0,0,1-.74-.75Z"/>
<path class="cls-9" d="M221.49,19a.74.74,0,0,1,.74-.74h1.53a.77.77,0,0,1,.75.74V43.07h11.31a.75.75,0,0,1,.75.74V45a.75.75,0,0,1-.75.75H222.23a.74.74,0,0,1-.74-.75Z"/>
<path class="cls-10" d="M124.62,56.16a15.13,15.13,0,0,1,10.44,4,.83.83,0,0,1,.05,1.2l-1.17,1.17c-.34.43-.69.39-1.12,0a13.05,13.05,0,0,0-8.25-3.24,12.42,12.42,0,0,0,0,24.82c3.76,0,6-1.51,8.25-3.24a.82.82,0,0,1,1-.13l1.3,1.17a.81.81,0,0,1,0,1.16,14.83,14.83,0,0,1-10.49,4.19,15.54,15.54,0,1,1,0-31.08Z"/>
<path class="cls-11" d="M141.37,57.41a.84.84,0,0,1,.82-.82h1.64a.82.82,0,0,1,.82.82v18c0,4.92,3.06,8.76,8.11,8.76s8.2-3.75,8.2-8.67V57.41a.82.82,0,0,1,.82-.82h1.64a.85.85,0,0,1,.82.82V75.67c0,6.56-4.66,11.57-11.48,11.57s-11.39-5-11.39-11.57Z"/>
<path class="cls-10" d="M172.66,57.41a.82.82,0,0,1,.82-.82h1.68a.85.85,0,0,1,.82.82V83.92h12.43a.81.81,0,0,1,.82.82V86a.82.82,0,0,1-.82.82H173.48a.82.82,0,0,1-.82-.82Z"/>
<path class="cls-10" d="M196.23,59.49h-7.51a.82.82,0,0,1-.82-.82V57.41a.82.82,0,0,1,.82-.82H207a.82.82,0,0,1,.82.82v1.26a.82.82,0,0,1-.82.82h-7.51V86a.85.85,0,0,1-.82.82h-1.64a.85.85,0,0,1-.82-.82Z"/>
<path class="cls-11" d="M212.2,57.41a.85.85,0,0,1,.82-.82h1.64a.82.82,0,0,1,.82.82v18c0,4.92,3.06,8.76,8.11,8.76s8.2-3.75,8.2-8.67V57.41a.82.82,0,0,1,.82-.82h1.64a.84.84,0,0,1,.82.82V75.67c0,6.56-4.66,11.57-11.48,11.57s-11.39-5-11.39-11.57Z"/>
<path class="cls-10" d="M243.49,57.41a.82.82,0,0,1,.82-.82h11.18a9.28,9.28,0,0,1,9.41,9.2,9.62,9.62,0,0,1-6.39,8.8l5.92,11a.82.82,0,0,1-.74,1.25h-2.2a.75.75,0,0,1-.69-.39L255.06,75h-8.25V86a.84.84,0,0,1-.82.82h-1.68a.82.82,0,0,1-.82-.82Zm11.79,14.72a6.2,6.2,0,1,0,0-12.39H246.9V72.13Z"/>
<path class="cls-10" d="M272,57.41a.82.82,0,0,1,.82-.82h17a.82.82,0,0,1,.82.82v1.26a.82.82,0,0,1-.82.82h-14.5V70h12.38a.84.84,0,0,1,.82.82v1.25a.82.82,0,0,1-.82.82H275.35v11h14.5a.82.82,0,0,1,.82.82V86a.82.82,0,0,1-.82.82h-17A.82.82,0,0,1,272,86Z"/>
<path class="cls-12" d="M75.27,98.73a.3.3,0,0,1,.28-.3h3.52a5.5,5.5,0,1,1,0,11H75.55a.3.3,0,0,1-.28-.3Zm3.55,9.61a4.42,4.42,0,1,0,0-8.84H76.46v8.84Z"/>
<path class="cls-12" d="M87,98.73a.3.3,0,0,1,.3-.3h6.19a.3.3,0,0,1,.3.3v.45a.3.3,0,0,1-.3.3H88.21v3.83h4.51a.31.31,0,0,1,.3.3v.46a.29.29,0,0,1-.3.29H88.21v4h5.28a.3.3,0,0,1,.3.3v.45a.3.3,0,0,1-.3.3H87.3a.3.3,0,0,1-.3-.3Z"/>
<path class="cls-12" d="M99.79,98.73a.3.3,0,0,1,.3-.3h.61a.31.31,0,0,1,.3.3v9.64h4.52a.3.3,0,0,1,.3.3v.45a.3.3,0,0,1-.3.3h-5.43a.3.3,0,0,1-.3-.3Z"/>
<path class="cls-13" d="M106.06,102.39c-.08-.08-.07-.24.09-.38a2.66,2.66,0,0,0,1-2,.55.55,0,0,1-.18,0,.91.91,0,0,1-.9-.9.89.89,0,0,1,.9-.89c.5,0,1,.28,1,1.41a4.32,4.32,0,0,1-1.32,2.9c-.15.15-.28.13-.37,0Z"/>
<path class="cls-14" d="M108.6,109l4.77-10.56a.29.29,0,0,1,.27-.18h.16a.26.26,0,0,1,.26.18L118.81,109a.28.28,0,0,1-.27.41h-.63a.3.3,0,0,1-.27-.17l-1.16-2.59h-5.57l-1.15,2.59a.27.27,0,0,1-.26.17h-.63A.28.28,0,0,1,108.6,109Zm7.46-3.33c-.77-1.71-1.52-3.44-2.29-5.15h-.13l-2.29,5.15Z"/>
<path class="cls-12" d="M120.52,98.73a.3.3,0,0,1,.3-.3h3.44a2.87,2.87,0,0,1,1.68,5.4,2.78,2.78,0,0,1,1.88,2.56,3.11,3.11,0,0,1-3.42,3h-3.58a.3.3,0,0,1-.3-.3Zm4,9.64a1.94,1.94,0,0,0,2-2,2.08,2.08,0,0,0-2.24-1.93h-2.59v3.93Zm-.27-5a1.81,1.81,0,0,0,1.88-2,1.74,1.74,0,0,0-1.88-1.89H121.7v3.85Z"/>
<path class="cls-12" d="M130.34,98.73a.31.31,0,0,1,.3-.3h.62a.31.31,0,0,1,.3.3v10.39a.31.31,0,0,1-.3.3h-.62a.31.31,0,0,1-.3-.3Z"/>
<path class="cls-12" d="M136.32,99.48h-2.73a.3.3,0,0,1-.3-.3v-.45a.3.3,0,0,1,.3-.3h6.66a.29.29,0,0,1,.29.3v.45a.29.29,0,0,1-.29.3h-2.74v9.64a.31.31,0,0,1-.29.3h-.6a.31.31,0,0,1-.3-.3Z"/>
<path class="cls-12" d="M142.27,98.73a.31.31,0,0,1,.3-.3h.63a.31.31,0,0,1,.3.3v10.39a.31.31,0,0,1-.3.3h-.63a.31.31,0,0,1-.3-.3Z"/>
<path class="cls-12" d="M146.7,98.73a.3.3,0,0,1,.3-.3h3.44a2.87,2.87,0,0,1,1.68,5.4,2.78,2.78,0,0,1,1.88,2.56,3.11,3.11,0,0,1-3.42,3H147a.3.3,0,0,1-.3-.3Zm4,9.64a2,2,0,0,0,2-2,2.09,2.09,0,0,0-2.25-1.93h-2.59v3.93Zm-.27-5a1.81,1.81,0,0,0,1.88-2,1.74,1.74,0,0,0-1.88-1.89h-2.56v3.85Z"/>
<path class="cls-12" d="M156.52,98.73a.31.31,0,0,1,.3-.3h.63a.31.31,0,0,1,.3.3v10.39a.31.31,0,0,1-.3.3h-.63a.31.31,0,0,1-.3-.3Z"/>
<path class="cls-15" d="M160.35,104.27V104a.29.29,0,0,1,.3-.3h3.28a.29.29,0,0,1,.3.3v.3a.28.28,0,0,1-.3.28h-3.28A.28.28,0,0,1,160.35,104.27Z"/>
<path class="cls-12" d="M168.16,99.48h-2.73a.29.29,0,0,1-.3-.3v-.45a.29.29,0,0,1,.3-.3h6.65a.29.29,0,0,1,.3.3v.45a.29.29,0,0,1-.3.3h-2.73v9.64a.31.31,0,0,1-.3.3h-.59a.31.31,0,0,1-.3-.3Z"/>
<path class="cls-16" d="M174.11,98.73a.3.3,0,0,1,.3-.3h6.19a.29.29,0,0,1,.29.3v.45a.29.29,0,0,1-.29.3h-5.28v3.83h4.51a.31.31,0,0,1,.3.3v.46a.3.3,0,0,1-.3.29h-4.51v4h5.28a.29.29,0,0,1,.29.3v.45a.29.29,0,0,1-.29.3h-6.19a.3.3,0,0,1-.3-.3Zm2-2a.22.22,0,0,1,.1-.3l2.35-1.32c.1-.06.33-.09.41,0l.28.57a.22.22,0,0,1-.09.33l-2.53,1c-.22.09-.3.09-.36,0Z"/>
<path class="cls-12" d="M184.65,98.49a.31.31,0,0,1,.28-.22h.25a.3.3,0,0,1,.27.18l3.11,8.65h.08l3.06-8.65a.3.3,0,0,1,.27-.18h.25a.31.31,0,0,1,.28.22l2,10.55c0,.22-.05.38-.29.38h-.62a.33.33,0,0,1-.29-.22l-1.39-8.09h-.07L189,109.4a.31.31,0,0,1-.26.18h-.29a.31.31,0,0,1-.26-.18l-2.92-8.29h-.07l-1.36,8.09a.31.31,0,0,1-.28.22h-.63c-.24,0-.33-.16-.29-.38Z"/>
<path class="cls-12" d="M197,98.73a.31.31,0,0,1,.3-.3h.62a.31.31,0,0,1,.3.3v10.39a.31.31,0,0,1-.3.3h-.62a.31.31,0,0,1-.3-.3Z"/>
<path class="cls-12" d="M200.67,107.77c.08-.09.16-.2.24-.3s.33-.33.55-.14a4.28,4.28,0,0,0,2.65,1.2,1.9,1.9,0,0,0,2.1-1.73c0-1.09-.94-1.73-2.74-2.48s-2.77-1.46-2.77-3.25c0-1.07.85-2.8,3.35-2.8a5.11,5.11,0,0,1,2.68.8.36.36,0,0,1,.1.54c-.07.09-.13.2-.19.29a.35.35,0,0,1-.55.15,4.3,4.3,0,0,0-2.06-.73c-1.66,0-2.17,1.07-2.17,1.73,0,1,.81,1.67,2.12,2.22,2.12.86,3.49,1.66,3.49,3.48a3.12,3.12,0,0,1-3.39,2.83,5.15,5.15,0,0,1-3.31-1.27A.35.35,0,0,1,200.67,107.77Z"/>
<path class="cls-12" d="M214.62,98.27a5.54,5.54,0,0,1,3.8,1.46.31.31,0,0,1,0,.44l-.42.43c-.13.15-.25.14-.41,0a4.75,4.75,0,0,0-3-1.18,4.52,4.52,0,0,0,0,9,4.55,4.55,0,0,0,3-1.18.3.3,0,0,1,.38,0l.47.42a.3.3,0,0,1,0,.42,5.38,5.38,0,0,1-3.81,1.53,5.66,5.66,0,1,1,0-11.31Z"/>
<path class="cls-14" d="M219.35,109l4.77-10.56a.29.29,0,0,1,.27-.18h.15a.29.29,0,0,1,.27.18L229.55,109a.28.28,0,0,1-.27.41h-.62a.29.29,0,0,1-.27-.17l-1.16-2.59h-5.58l-1.14,2.59a.29.29,0,0,1-.27.17h-.63A.27.27,0,0,1,219.35,109Zm7.45-3.33c-.77-1.71-1.52-3.44-2.29-5.15h-.12l-2.3,5.15Z"/>
<path class="cls-12" d="M232.51,98.49a.3.3,0,0,1,.28-.22H233a.3.3,0,0,1,.27.18l3.11,8.65h.07l3.07-8.65a.28.28,0,0,1,.26-.18h.25a.31.31,0,0,1,.29.22l2,10.55c.05.22,0,.38-.28.38h-.63a.32.32,0,0,1-.28-.22l-1.4-8.09h-.06l-2.89,8.29a.31.31,0,0,1-.27.18h-.28a.34.34,0,0,1-.27-.18l-2.92-8.29H233l-1.37,8.09a.29.29,0,0,1-.28.22h-.63c-.23,0-.33-.16-.28-.38Z"/>
<path class="cls-12" d="M244.81,98.73a.31.31,0,0,1,.29-.3h.63a.31.31,0,0,1,.3.3v10.39a.31.31,0,0,1-.3.3h-.63a.31.31,0,0,1-.29-.3Z"/>
<path class="cls-12" d="M249.24,98.56a.3.3,0,0,1,.29-.29h.4L257,107.1h0V98.73a.29.29,0,0,1,.3-.3h.55a.31.31,0,0,1,.29.3v10.56a.3.3,0,0,1-.29.29h-.29l-7.2-9h0v8.54a.29.29,0,0,1-.3.3h-.55a.31.31,0,0,1-.29-.3Z"/>
<path class="cls-12" d="M266.26,98.27a5.54,5.54,0,0,1,3.8,1.46.31.31,0,0,1,0,.44c-.14.14-.31.3-.44.44s-.23.14-.4,0a4.78,4.78,0,0,0-3-1.23,4.53,4.53,0,0,0,0,9,5.92,5.92,0,0,0,2.83-.66v-2.2h-1.81a.29.29,0,0,1-.3-.28v-.59a.29.29,0,0,1,.3-.29H270a.29.29,0,0,1,.28.29v3.6a.39.39,0,0,1-.12.25,7.73,7.73,0,0,1-3.88,1,5.66,5.66,0,1,1,0-11.31Z"/>
<path class="cls-17" d="M272.75,98.73a.31.31,0,0,1,.3-.3h.59a.3.3,0,0,1,.3.3v6.55a3,3,0,1,0,5.94,0V98.73a.29.29,0,0,1,.29-.3h.6a.31.31,0,0,1,.3.3v6.64a4.16,4.16,0,1,1-8.32,0Z"/>
<path class="cls-12" d="M284.13,98.73a.3.3,0,0,1,.3-.3h6.19a.3.3,0,0,1,.3.3v.45a.3.3,0,0,1-.3.3h-5.28v3.83h4.51a.31.31,0,0,1,.3.3v.46a.29.29,0,0,1-.3.29h-4.51v4h5.28a.3.3,0,0,1,.3.3v.45a.3.3,0,0,1-.3.3h-6.19a.3.3,0,0,1-.3-.3Z"/>
</g>
<g>
<path class="cls-18" d="M75.21,56.76a.35.35,0,0,1,.34-.36h4.31a6.73,6.73,0,1,1,0,13.45H75.55a.36.36,0,0,1-.34-.37Zm4.34,11.76a5.41,5.41,0,1,0,0-10.82H76.67V68.52Z"/>
<path class="cls-18" d="M89.55,56.76a.37.37,0,0,1,.37-.36h7.57a.37.37,0,0,1,.37.36v.56a.37.37,0,0,1-.37.36H91v4.69h5.52a.38.38,0,0,1,.36.37v.56a.36.36,0,0,1-.36.36H91v4.9h6.46a.37.37,0,0,1,.37.37v.55a.38.38,0,0,1-.37.37H89.92a.38.38,0,0,1-.37-.37Z"/>
</g>
<g>
<path class="cls-19" d="M75.29,74.75a.34.34,0,0,1,.34-.34h.69a.35.35,0,0,1,.33.34V85.6h5.09a.34.34,0,0,1,.34.33v.51a.34.34,0,0,1-.34.34H75.63a.34.34,0,0,1-.34-.34Z"/>
<path class="cls-20" d="M86.35,86.32l5.37-11.89a.3.3,0,0,1,.3-.19h.17a.33.33,0,0,1,.31.19l5.33,11.89a.31.31,0,0,1-.3.46h-.71a.35.35,0,0,1-.3-.19l-1.3-2.92H88.94l-1.29,2.92a.33.33,0,0,1-.3.19h-.7A.31.31,0,0,1,86.35,86.32Zm8.39-3.74c-.87-1.93-1.71-3.87-2.58-5.8H92l-2.58,5.8Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
const { loginFields, login } = useAuthActions();
</script>
<template>
<UAuthForm
:schema="loginSchema"
:fields="loginFields"
title="Connexion"
description="Veuillez vous identifier."
icon="i-lucide-user"
loading-auto
@submit="login"
/>
</template>

View File

@@ -0,0 +1,24 @@
<script setup lang="ts">
const { logout } = useAuthActions();
</script>
<template>
<div class="w-full space-y-6">
<div class="flex flex-col text-center">
<div class="text-xl text-pretty font-semibold text-highlighted">
Déconnexion
</div>
<div class="mt-1 text-base text-pretty text-muted">
Veuillez confirmer la déconnexion.
</div>
</div>
<UButton
icon="i-lucide-log-out"
block
loading-auto
to="#"
label="Déconnexion"
@click="logout()"
/>
</div>
</template>

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
</script>
<template>
<div class="w-full space-y-6">
<div class="flex flex-col text-center">
<div class="text-xl text-pretty font-semibold text-highlighted">
Redirection en cours
</div>
<div class="mt-1 text-base text-pretty text-muted">
Veuillez patienter...
</div>
</div>
</div>
</template>

View File

@@ -0,0 +1,3 @@
fragment TheArticle on Post {
title
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import type { TheArticleFragment } from "#graphql-operations";
const props = defineProps<TheArticleFragment>();
useSeoMeta({ title: props.title });
</script>
<template>
<UPage>
<UPageSection v-if="title" :title="title" />
</UPage>
</template>

View File

@@ -0,0 +1,3 @@
fragment TheEvent on Event {
title
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import type { TheEventFragment } from "#graphql-operations";
const props = defineProps<TheEventFragment>();
useSeoMeta({ title: props.title });
</script>
<template>
<UPage>
<UPageSection v-if="title" :title="title" />
</UPage>
</template>

View File

@@ -0,0 +1,3 @@
fragment TheListing on Listing {
title
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import type { TheListingFragment } from "#graphql-operations";
const props = defineProps<TheListingFragment>();
useSeoMeta({ title: props.title });
</script>
<template>
<UPage>
<UPageSection v-if="title" :title="title" />
</UPage>
</template>

View File

@@ -0,0 +1,3 @@
fragment TheLocation on Location {
title
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import type { TheLocationFragment } from "#graphql-operations";
const props = defineProps<TheLocationFragment>();
useSeoMeta({ title: props.title });
</script>
<template>
<UPage>
<UPageSection v-if="title" :title="title" />
</UPage>
</template>

View File

@@ -0,0 +1,16 @@
fragment ThePage on Page {
title
template {
__typename
}
children {
nodes {
uri
}
}
groupPostPage {
sections {
...TheSection
}
}
}

View File

@@ -0,0 +1,16 @@
<script setup lang="ts">
import type { ThePageFragment } from "#graphql-operations";
const props = defineProps<ThePageFragment>();
if (props.template?.__typename === "Template_VirtualPage") {
useRobotsRule({ noindex: true });
await navigateTo(props.children?.nodes[0]?.uri || "/");
}
useSeoMeta({ title: props.title });
</script>
<template>
<TheSections :sections="groupPostPage?.sections || []" />
</template>

View File

@@ -0,0 +1,3 @@
fragment TheProfile on Profile {
title
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import type { TheProfileFragment } from "#graphql-operations";
const props = defineProps<TheProfileFragment>();
useSeoMeta({ title: props.title });
</script>
<template>
<UPage>
<UPageSection v-if="title" :title="title" />
</UPage>
</template>

View File

@@ -0,0 +1,3 @@
fragment TheProject on Project {
title
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import type { TheProjectFragment } from "#graphql-operations";
const props = defineProps<TheProjectFragment>();
useSeoMeta({ title: props.title });
</script>
<template>
<UPage>
<UPageSection v-if="title" :title="title" />
</UPage>
</template>

View File

@@ -0,0 +1,3 @@
fragment TheResource on Resource {
title
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import type { TheResourceFragment } from "#graphql-operations";
const props = defineProps<TheResourceFragment>();
useSeoMeta({ title: props.title });
</script>
<template>
<UPage>
<UPageSection v-if="title" :title="title" />
</UPage>
</template>

View File

@@ -0,0 +1,6 @@
fragment SectionTextBlock on GroupAbstractBuilderSectionsTextBlockLayout {
content
layoutSettings {
...SectionWrapper
}
}

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import type { SectionTextBlockFragment } from "#graphql-operations";
defineProps<SectionTextBlockFragment>();
</script>
<template>
<section data-section-type="text-block">
<div :class="layoutSettings?.contentWidth" v-html="content" />
</section>
</template>

View File

@@ -0,0 +1,4 @@
fragment SectionWrapper on GroupAbstractBuilderSectionsLayoutSettings {
bgColor
contentWidth
}

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
import type { SectionWrapperFragment } from "#graphql-operations";
defineProps<SectionWrapperFragment>();
</script>
<template>
<section :class="bgColor">
<div :class="contentWidth">
<slot />
</div>
</section>
</template>

View File

@@ -0,0 +1,6 @@
fragment TheSection on GroupAbstractBuilderSections_Layout {
__typename
... on GroupAbstractBuilderSectionsTextBlockLayout {
...SectionTextBlock
}
}

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import type { TheSectionFragment } from "#graphql-operations";
const props = defineProps<{ sections: (TheSectionFragment | null)[] }>();
const sections = props.sections.filter(Boolean).map((section) => useSection(section!));
</script>
<template>
<SectionWrapper v-for="({ component, attrs }, i) in sections" :key="i" v-bind="attrs.layoutSettings || {}">
<component :is="component" v-bind="attrs" />
</SectionWrapper>
</template>

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import type { BreadcrumbItem } from "@nuxt/ui";
defineProps<{ breadcrumbs: BreadcrumbItem[] }>();
</script>
<template>
<UContainer>
<UBreadcrumb :items="breadcrumbs" />
</UContainer>
</template>

View File

@@ -0,0 +1,16 @@
<script setup lang="ts">
const props = defineProps<{ showLabels: boolean }>();
const { isLoggedIn } = useAuth();
const label = computed(() => props.showLabels ? (isLoggedIn.value ? "Déconnexion" : "Connexion") : undefined);
</script>
<template>
<AuthState>
<UButton
:icon="isLoggedIn ? 'i-lucide-log-out' : 'i-lucide-log-in'"
color="neutral"
to="/connexion"
:label="label"
/>
</AuthState>
</template>

View File

@@ -0,0 +1,17 @@
<script setup lang="ts">
const props = defineProps<{ showLabels: boolean }>();
const { isLoggedIn } = useAuth();
const label = computed(() => props.showLabels ? (isLoggedIn.value ? "Espace membre" : "Devenir membre") : undefined);
const to = computed(() => isLoggedIn.value ? "/espace-membre" : "/devenir-membre");
</script>
<template>
<AuthState>
<UButton
icon="i-lucide-user"
color="primary"
:label="label"
:to="to"
/>
</AuthState>
</template>

View File

@@ -0,0 +1,5 @@
<template>
<UFooter>
TODO
</UFooter>
</template>

View File

@@ -0,0 +1,11 @@
<template>
<div class="container-fluid flex flex-col lg:flex-row justify-between items-center gap-x-6 gap-y-3 py-3 text-muted text-sm text-center">
<p class="flex-break-words">
© {{ new Date().getFullYear() }} Conseil de la culture de l'Abitibi-Témiscamingue.
</p>
<p class="flex items-center gap-1">
Fait avec <UIcon name="i-lucide-heart" /> par
<ULink href="https://websimple.com" target="_blank" external title="Site web développé par Websimple">Websimple</ULink>
</p>
</div>
</template>

View File

@@ -0,0 +1,19 @@
<script setup lang="ts">
const { menuItems } = await useMenuItems("MAIN");
</script>
<template>
<UHeader title="CCAT" mode="slideover">
<template #left>
<NuxtLink to="/">
<SvgLogoCcat class="h-12 w-auto shrink-0" />
</NuxtLink>
</template>
<template #right>
<UNavigationMenu :items="menuItems" variant="link" content-orientation="vertical" class="hidden lg:block" :ui="{ list: '-mx-2.5', link: 'text-base', childLink: 'text-base' }" />
</template>
<template #body>
<UNavigationMenu :items="menuItems" orientation="vertical" />
</template>
</UHeader>
</template>

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
const { profiles } = await useSiteOptions();
const { menuItems } = await useMenuItems("TOP");
const { breakpoints } = useResponsive();
const showLabels = breakpoints.greaterOrEqual("sm");
</script>
<template>
<UContainer class="flex items-center gap-1.5">
<UiSocialProfiles :profiles="profiles" class="mr-auto" />
<UNavigationMenu :items="menuItems" variant="link" content-orientation="vertical" />
<SiteHeaderTopAuth :show-labels="showLabels" />
<SiteHeaderTopMember :show-labels="showLabels" />
</UContainer>
</template>

View File

@@ -0,0 +1,39 @@
<script setup lang="ts">
import type { SiteOptionsFragment } from "#graphql-operations";
defineProps<{ profiles: SiteOptionsFragment["profiles"] }>();
const socialIconMap = {
"facebook.com": "i-cib-facebook-f",
"twitter.com": "i-cib-twitter",
"x.com": "i-cib-twitter",
"instagram.com": "i-cib-instagram",
"youtube.com": "i-cib-youtube",
"linkedin.com": "i-cib-linkedin",
"tiktok.com": "i-cib-tiktok",
};
function getIconFromUrl(url: string): string {
try {
const domain = new URL(url).hostname.toLowerCase().replace(/^www\./, "");
return socialIconMap[domain as keyof typeof socialIconMap] || "i-lucide-globe";
}
catch {
return "i-lucide-globe";
}
}
</script>
<template>
<div class="flex gap-1">
<UButton
v-for="(profile, key) in profiles" :key="key"
:icon="getIconFromUrl(profile!.url)"
:to="profile!.url"
variant="link"
color="neutral"
external
target="_blank"
/>
</div>
</template>

View File

@@ -0,0 +1,107 @@
import type { FormSubmitEvent } from "@nuxt/ui";
export function useAuth() {
const { loggedIn, session } = useUserSession();
const isLoggedIn = loggedIn;
const isSwitchedTo = computed(() => Boolean(session.value?.isSwitchedTo));
const hasRole = (role: string) => session.value?.user?.roles?.includes(role) || false;
const isAdmin = computed(() => hasRole("administrator"));
return { isLoggedIn, isSwitchedTo, hasRole, isAdmin };
}
const isRedirecting = ref(false);
export function useAuthActions() {
const { fetch: refreshUserSession } = useUserSession();
const routeRedirect = useRoute().query.redirect as string || undefined;
const toast = useToast();
async function redirectTo(to: string | undefined) {
isRedirecting.value = true;
await delay(1000);
await refreshUserSession();
await navigateTo(to || routeRedirect || "/");
await nextTick();
isRedirecting.value = false;
}
// Login
const loginFields = [
{
name: "email",
type: "text" as const,
label: "Courriel",
placeholder: "Entrez votre courriel",
required: true,
}, {
name: "password",
label: "Mot de passe",
type: "password" as const,
placeholder: "Entrez votre mot de passe",
required: true,
},
];
async function login({ data: args }: FormSubmitEvent<LoginOutput>, redirect?: string) {
try {
const { data, errors } = await useGraphqlMutation("login", args);
if (errors.length || !data.login) {
console.error(errors);
throw new Error("Une erreur est survenue.");
}
await redirectTo(redirect);
}
catch (error) {
const message = error instanceof Error ? error.message : "Une erreur est survenue.";
toast.add({ title: "Échec de la connexion", description: message, color: "error" });
}
}
// Logout
async function logout(redirect?: string) {
try {
const result = await $fetch("/api/logout", { method: "POST" });
if (!result.success) {
throw new Error("Une erreur est survenue.");
}
await redirectTo(redirect);
}
catch (error) {
const message = error instanceof Error ? error.message : "Une erreur est survenue.";
toast.add({ title: "Échec de la déconnexion", description: message, color: "error" });
}
}
// Switch to
async function switchTo(userId: number, redirect?: string) {
try {
const { data, errors } = await useGraphqlMutation("switchTo", { userId });
if (errors.length || !data.switchTo) {
throw new Error("Une erreur est survenue");
}
await redirectTo(redirect);
}
catch (error) {
const message = error instanceof Error ? error.message : "Une erreur est survenue";
toast.add({ title: "Échec du changement d'utilisateur", description: message, color: "error" });
}
}
// Switch back
async function switchBack(redirect?: string) {
try {
const result = await $fetch("/api/switch-back", { method: "POST" });
if (!result.success) {
throw new Error("Une erreur est survenue.");
}
await redirectTo(redirect);
}
catch (error) {
const message = error instanceof Error ? error.message : "Une erreur est survenue";
toast.add({ title: "Échec du changement d'utilisateur", description: message, color: "error" });
}
}
return { isRedirecting, loginFields, login, logout, switchTo, switchBack };
}

View File

@@ -0,0 +1,3 @@
export function useMemberArea() {
return {};
}

View File

@@ -0,0 +1,3 @@
export function useMemberSignup() {
return {};
}

View File

@@ -0,0 +1,14 @@
import type { MenuLocationEnum } from "#graphql-operations";
import type { NavigationMenuItem } from "@nuxt/ui";
export async function useMenuItems(location: MenuLocationEnum) {
const { data } = await useAsyncGraphqlQuery("menuItems", { location }, { graphqlCaching: { client: true } });
if (data.value?.errors?.length) {
throw createError({ statusCode: 500, message: "Erreur lors de la récupération des éléments de menu" });
}
const menuItems: NavigationMenuItem[] = (data.value?.data.menuItems?.nodes || []).map(({ childItems, ...menuItem }) => ({
...menuItem,
children: childItems?.nodes || [],
}));
return { menuItems };
}

View File

@@ -0,0 +1,31 @@
import { ThePage, TheArticle, TheEvent, TheListing, TheLocation, TheProfile, TheProject, TheResource } from "#components";
const nodes = {
Event: TheEvent,
Location: TheLocation,
Listing: TheListing,
Profile: TheProfile,
Page: ThePage,
Post: TheArticle,
Project: TheProject,
Resource: TheResource,
} as const;
export async function useNodeByUri(uri: string) {
const { data, error } = await useAsyncGraphqlQuery("nodeByUri", { uri }, { graphqlCaching: { client: true } });
if (error.value) {
throw createError({ statusCode: 500, statusMessage: "Erreur interne", message: error.value.message });
}
if (data.value?.errors.length) {
throw createError({ statusCode: 500, statusMessage: "Erreur interne", message: data.value.errors.map((error) => error.message).join("\n") });
}
if (!data.value?.data.nodeByUri) {
throw createError({ statusCode: 500, statusMessage: "Erreur interne", message: "La page n'a retourné aucunes données." });
}
const { __typename, breadcrumbs, ...attrs } = data.value.data.nodeByUri;
const component = nodes[__typename as keyof typeof nodes] || null;
if (!component) {
throw createError({ statusCode: 500, statusMessage: "Erreur interne", message: "Le type de page est invalide." });
}
return { component, breadcrumbs: breadcrumbs || [], attrs };
}

View File

@@ -0,0 +1,11 @@
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
export function useResponsive() {
const { isMobileOrTablet } = useDevice();
const breakpoints = useBreakpoints(breakpointsTailwind, { ssrWidth: isMobileOrTablet ? 375 : 1024 });
return {
breakpoints,
isDesktop: breakpoints.greaterOrEqual("lg"),
};
}

View File

@@ -0,0 +1,13 @@
export async function useSiteOptions() {
const { data, error } = await useAsyncGraphqlQuery("siteOptions", {}, { graphqlCaching: { client: true } });
if (error.value) {
throw createError({ statusCode: 500, statusMessage: "Erreur interne", message: error.value.message });
}
if (data.value?.errors.length) {
throw createError({ statusCode: 500, statusMessage: "Erreur interne", message: data.value.errors.map((error) => error.message).join("\n") });
}
if (!data.value?.data.siteOptions?.groupCcat) {
throw createError({ statusCode: 500, statusMessage: "Erreur interne", message: "Options du site invalides." });
}
return { ...data.value?.data.siteOptions?.groupCcat };
}

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import type { NuxtError } from "#app";
defineProps<{ error: NuxtError }>();
</script>
<template>
<UApp>
<UError :error="error" />
</UApp>
</template>

View File

@@ -0,0 +1,9 @@
mutation login($email: String!, $password: String!) {
login(input: { username: $email, password: $password }) {
authToken
refreshToken
user {
...AuthUser
}
}
}

View File

@@ -0,0 +1,19 @@
fragment MenuItem on MenuItem {
id
label
to: path
target
}
query menuItems($location: MenuLocationEnum!) {
menuItems(where: {location: $location, parentDatabaseId: 0}) {
nodes {
...MenuItem
childItems {
nodes {
...MenuItem
}
}
}
}
}

View File

@@ -0,0 +1,31 @@
query nodeByUri($uri: String!) {
nodeByUri(uri: $uri) {
__typename
id
breadcrumbs {
label
to
}
... on Page {
...ThePage
}
... on Post {
...TheArticle
}
... on Event {
...TheEvent
}
... on Location {
...TheLocation
}
... on Profile {
...TheProfile
}
... on Project {
...TheProject
}
... on Resource {
...TheResource
}
}
}

View File

@@ -0,0 +1,13 @@
fragment SiteOptions on GroupCcat {
profiles {
url
}
}
query siteOptions {
siteOptions {
groupCcat {
...SiteOptions
}
}
}

View File

@@ -0,0 +1,9 @@
mutation switchTo($userId: ID!) {
switchTo(input: { userId: $userId }) {
authToken
refreshToken
user {
...AuthUser
}
}
}

View File

@@ -0,0 +1,19 @@
<template>
<div class="h-screen flex items-center justify-center px-4">
<UButton
icon="i-lucide-chevron-left"
to="/"
size="xl"
color="neutral"
variant="subtle"
class="absolute left-8 top-8 rounded-full z-10"
/>
<UPageCard
variant="subtle"
class="max-w-sm w-full"
>
<slot />
</UPageCard>
</div>
</template>

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
const refSiteFooterBottom = useTemplateRef("refSiteFooterBottom");
const { height } = useElementSize(refSiteFooterBottom);
watch(height, (h) => {
document.documentElement.style.setProperty("--footer-bottom-height", `${h}px`);
});
</script>
<template>
<div id="layout-default">
<TheSiteHeaderTop />
<TheSiteHeader />
<div class="relative z-main bg-white border-b border-muted mb-[var(--footer-bottom-height)]">
<UMain>
<slot />
</UMain>
<TheSiteFooter />
</div>
<div ref="refSiteFooterBottom" class="fixed bottom-0 w-full bg-muted">
<TheSiteFooterBottom />
</div>
</div>
</template>

View File

@@ -0,0 +1,18 @@
export default defineNuxtRouteMiddleware((to) => {
const { isLoggedIn, hasRole } = useAuth();
if (!isLoggedIn.value) {
return navigateTo(`/connexion?redirect=${encodeURIComponent(to.fullPath)}`);
}
if (!to.meta.role) {
throw createError({ statusCode: 500, statusMessage: "Erreur serveur", message: "Le paramètre 'role' est requis (hasRole)." });
}
if (!hasRole(to.meta.role)) {
throw createError({ statusCode: 403, statusMessage: "Accès refusé", message: `Le rôle '${to.meta.role}' est requis.` });
}
});
declare module "#app" {
interface PageMeta {
role?: string;
}
}

View File

@@ -0,0 +1,12 @@
export default defineNuxtRouteMiddleware((to) => {
const { isLoggedIn, isAdmin } = useAuth();
if (!isLoggedIn.value) {
return navigateTo(`/connexion?redirect=${encodeURIComponent(to.fullPath)}`);
}
if (!isAdmin.value) {
throw createError({
statusCode: 403,
statusMessage: "Accès refusé - Privilèges administrateur requis",
});
}
});

View File

@@ -0,0 +1,6 @@
export default defineNuxtRouteMiddleware((to) => {
const { isLoggedIn } = useAuth();
if (!isLoggedIn.value) {
return navigateTo(`/connexion?redirect=${encodeURIComponent(to.fullPath)}`);
}
});

View File

@@ -0,0 +1,6 @@
export default defineNuxtRouteMiddleware((to) => {
const { isLoggedIn } = useAuth();
if (isLoggedIn.value) {
return navigateTo(`/connexion?redirect=${encodeURIComponent(to.fullPath)}`);
}
});

Some files were not shown because too many files have changed in this diff Show More