Skip to content
This repository has been archived by the owner on Sep 3, 2024. It is now read-only.

WIP - Migrate messaging scheme #212

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Binary file modified dashboard/bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"svelte-radix": "^1.1.0",
"tailwind-merge": "^2.2.2",
"tailwind-variants": "^0.2.1",
"webext-bridge": "^6.0.1",
"zod-to-json-schema": "^3.22.4"
},
"optionalDependencies": {
Expand Down
15 changes: 8 additions & 7 deletions dashboard/src/lib/firebase/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { GithubAuthProvider, GoogleAuthProvider, signInWithPopup } from 'firebase/auth';

import { auth } from '.';
import { identifyMixpanelUser } from '$lib/mixpanel/client';
import { FirebaseService } from '$lib/storage';
import { USER_ID_KEY } from '$lib/utils/constants';
import {
githubHistoryMapStore,
projectsMapStore,
Expand All @@ -9,17 +11,16 @@ import {
usersMapStore
} from '$lib/utils/store';
import { FirestoreCollections } from '$shared/constants';
import { MessageType, MessageService } from '$shared/message';
import { FirebaseService } from '$lib/storage';
import { MessageType, } from '$shared/message';
import type { User } from '$shared/models';
import { identifyMixpanelUser } from '$lib/mixpanel/client';
import { USER_ID_KEY } from '$lib/utils/constants';
import { sendMessage } from 'webext-bridge/window';
import { auth } from '.';

export function subscribeToFirebaseAuthChanges() {
auth.onAuthStateChanged((authUser) => {
if (authUser) {
// Send authUser to extension
MessageService.getInstance().publish(MessageType.DASHBOARD_SIGN_IN, authUser);
sendMessage(MessageType.DASHBOARD_SIGN_IN, JSON.stringify(authUser) as any);

// Listen and update user from remote
(new FirebaseService<User>(FirestoreCollections.USERS)).subscribe(authUser.uid, (user) => {
Expand All @@ -33,7 +34,7 @@ export function subscribeToFirebaseAuthChanges() {
});
localStorage.setItem(USER_ID_KEY, authUser.uid);
} else {
MessageService.getInstance().publish(MessageType.DASHBOARD_SIGN_OUT);
sendMessage(MessageType.DASHBOARD_SIGN_OUT, {});
// Clear data when signed out
userStore.set(undefined);
usersMapStore.set(new Map());
Expand Down
11 changes: 7 additions & 4 deletions dashboard/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<script lang="ts">
import '../app.css';
import { onMount } from 'svelte';
import { subscribeToFirebaseAuthChanges } from '$lib/firebase/auth';
import { SvelteToast } from '@zerodevx/svelte-toast';
import { page } from '$app/stores';
import { subscribeToFirebaseAuthChanges } from '$lib/firebase/auth';
import { trackMixpanelEvent } from '$lib/mixpanel/client';
import { MESSAGING_NAMESPACE } from '$shared/message';
import { SvelteToast } from '@zerodevx/svelte-toast';
import { onMount } from 'svelte';
import { setNamespace } from 'webext-bridge/window';
import '../app.css';

onMount(() => {
setNamespace(MESSAGING_NAMESPACE);
subscribeToFirebaseAuthChanges();
trackMixpanelEvent('Page View', { page: $page.route.id });
});
Expand Down
6 changes: 3 additions & 3 deletions dashboard/src/routes/dashboard/CreateProjectModal.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<script lang="ts">
import { trackMixpanelEvent } from '$lib/mixpanel/client';
import { MessageService, MessageType } from '$shared/message';
import { MessageType } from '$shared/message';
import { ArrowRight, Plus } from 'svelte-radix';

import Button from '$lib/components/ui/button/button.svelte';
import * as Dialog from '$lib/components/ui/dialog';
import Input from '$lib/components/ui/input/input.svelte';
import { ExternalLinks } from '$shared/constants';
import { sendMessage } from 'webext-bridge/window';

export let modalOpen = false;
let inputUrl = '';
Expand All @@ -29,12 +30,11 @@
}
}
errorText = '';
console.log('Creating project from URL:', inputUrl);
openUrl(inputUrl);
}

function openUrl(url: string) {
MessageService.getInstance().publish(MessageType.OPEN_URL, { url, inject: true });
sendMessage(MessageType.OPEN_URL, { url, inject: true });
url = '';
modalOpen = false;
trackMixpanelEvent('Create Project from dashboard', { url });
Expand Down
7 changes: 3 additions & 4 deletions dashboard/src/routes/dashboard/projects/[id]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
import { projectsMapStore, userStore, usersMapStore } from '$lib/utils/store';
import { DashboardRoutes, FirestoreCollections, LengthSettings } from '$shared/constants';
import { truncateString } from '$shared/helpers';
import { MessageService, MessageType } from '$shared/message';
import { MessageType } from '$shared/message';
import type { Activity, Project, User } from '$shared/models';
import { onDestroy, onMount } from 'svelte';
import { ArrowLeft, ExclamationTriangle, Pencil2, Reload, Shadow } from 'svelte-radix';
import { sendMessage } from 'webext-bridge/window';

import ProjectTour from '$lib/components/tour/ProjectTour.svelte';
import * as Breadcrumb from '$lib/components/ui/breadcrumb/index.js';
Expand All @@ -23,7 +24,6 @@
import GithubModal from './github/GithubModal.svelte';

let project: Project | undefined;
let messageService: MessageService;
const projectService = new FirebaseService<Project>(FirestoreCollections.PROJECTS);
const userService = new FirebaseService<User>(FirestoreCollections.USERS);

Expand All @@ -41,7 +41,6 @@
}

onMount(async () => {
messageService = MessageService.getInstance();
auth.onAuthStateChanged((user) => {
if (!user) {
goto(DashboardRoutes.SIGNIN);
Expand Down Expand Up @@ -99,7 +98,7 @@
});

function requestEditProject() {
messageService.publish(MessageType.EDIT_PROJECT, project);
sendMessage(MessageType.EDIT_PROJECT, { project } as any);
trackMixpanelEvent('Edit project from dashboard', {
projectId: project?.id,
projectName: project?.name,
Expand Down
Binary file modified editor/bun.lockb
Binary file not shown.
2 changes: 0 additions & 2 deletions editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@
"@twind/core": "^1.1.3",
"@twind/preset-autoprefix": "^1.0.7",
"@twind/preset-tailwind": "^1.1.4",
"async-retry": "^1.3.3",
"bits-ui": "^0.21.10",
"blingblingjs": "^2.3.0",
"clsx": "^2.1.0",
"cmdk-sv": "^0.0.13",
"codemirror": "^6.0.1",
Expand Down
2 changes: 1 addition & 1 deletion editor/src/lib/components/Editor.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { ToolManager, ToolName } from "$lib/tools";
import { EventListenerService } from "./listener";
import { EventListenerService } from "../listener";
import { onMount } from "svelte";
import { setNamespace } from "webext-bridge/window";
import { MESSAGING_NAMESPACE } from "$shared/message";
Expand Down
21 changes: 0 additions & 21 deletions editor/src/lib/components/listener/index.ts

This file was deleted.

19 changes: 19 additions & 0 deletions editor/src/lib/listener/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ProjectChangeService } from "$lib/project"
import { MessageType } from "$shared/message"
import type { Project } from "$shared/models"
import { onMessage } from "webext-bridge/window"

export class EventListenerService {
constructor() { }

listen() {
onMessage(MessageType.APPLY_PROJECT_CHANGE, async ({ data }) => {
const project: Project = data as any
const { project: updatedProject, shouldSaveProject } = await new ProjectChangeService().applyProjectChanges(project)

// Should send mutated project
// if (shouldSaveProject)
// sendMessage(MessageType.PUBLISH_PROJECT, updatedProject as any)
})
}
}
Original file line number Diff line number Diff line change
@@ -1,57 +1,21 @@
import { convertChangeObjectToEditEvents, convertStructureChangeToEditEvents } from "$lib/editEvents/convert";
import { getCSSFramework } from "$lib/utils/styleFramework";
import { MessageService, MessageType } from "$shared/message";
import { applyEvent, createReverseEvent } from "$lib/tools/edit/history";
import { convertChangeObjectToEditEvents, convertStructureChangeToEditEvents } from "$shared/helpers";
import { StyleFramework } from "$shared/models";

import { EditType, type Activity, type EditEvent, type Project } from "$shared/models";

export class ProjectChangeService {
constructor() { }

mergeProjects(currentProject: Project, targetProject: Project): Project {
const currentActivities = currentProject.activities || {};
const targetActivities = targetProject.activities || {};

const mergedActivities = { ...targetActivities };

Object.keys(currentActivities).forEach(activityKey => {
const currentActivity = currentActivities[activityKey];
const targetActivity = mergedActivities[activityKey] || {};


// Merge style changes
const currentStyles = currentActivity.styleChanges || {};
const targetStyles = targetActivity.styleChanges || {};
targetActivity.styleChanges = { ...targetStyles, ...currentStyles };

// Merge text changes
const currentTexts = currentActivity.textChanges || {};
const targetTexts = targetActivity.textChanges || {};
targetActivity.textChanges = { ...targetTexts, ...currentTexts };

// Merge attribute changes
const currentAttributes = currentActivity.attributeChanges || {};
const targetAttributes = targetActivity.attributeChanges || {};
targetActivity.attributeChanges = { ...targetAttributes, ...currentAttributes };

mergedActivities[activityKey] = { ...currentActivity, ...targetActivity };
});

return {
...targetProject,
updatedAt: currentProject.updatedAt,
activities: mergedActivities
};
}


async applyProjectChanges(project: Project, revert: boolean = false): Promise<boolean> {
if (!project) return false

async applyProjectChanges(project: Project, revert: boolean = false): Promise<{ project: Project, shouldSaveProject: boolean }> {
let shouldSaveProject = false
if (!project) return { project, shouldSaveProject }

const editEvents = this.getEditEventsFromProject(project)
if (editEvents.length > 0) {
MessageService.getInstance().publish(revert ? MessageType.REVERT_EDIT_EVENTS : MessageType.APPLY_EDIT_EVENTS, editEvents)
editEvents.forEach(event => {
revert ? applyEvent(createReverseEvent(event), false) : applyEvent(event, false)
})
shouldSaveProject = true
}

Expand All @@ -66,23 +30,15 @@ export class ProjectChangeService {

// Get style framework if did not exist
if (!project.projectSettings?.styleFramework) {
const styleFramework = await getCSSFramework()
const styleFramework = await this.getCSSFramework()
project.projectSettings = {
...project.projectSettings,
styleFramework
}
shouldSaveProject = true
}

return shouldSaveProject
}

getEditEventsFromProject(project: Project): EditEvent[] {
const editEvents: EditEvent[] = []
for (const activity of Object.values(project.activities)) {
editEvents.push(...this.getEditEventsFromActivity(activity))
}
return editEvents
return { project, shouldSaveProject }
}

updateActivityPath(activity: Activity): boolean {
Expand All @@ -97,6 +53,14 @@ export class ProjectChangeService {
return false
}

getEditEventsFromProject(project: Project): EditEvent[] {
const editEvents: EditEvent[] = []
for (const activity of Object.values(project.activities)) {
editEvents.push(...this.getEditEventsFromActivity(activity))
}
return editEvents
}

getEditEventsFromActivity(activity: Activity): EditEvent[] {
const editEvents: EditEvent[] = []
for (const [key, changeValues] of Object.entries(activity.styleChanges)) {
Expand Down Expand Up @@ -138,4 +102,45 @@ export class ProjectChangeService {
editEvents.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
return editEvents
}

async isTailwindUsed() {
// Function to fetch and read the content of a stylesheet
async function fetchStylesheet(href: string) {
try {
const response = await fetch(href);
return await response.text();
} catch (error) {
console.error('Error fetching the stylesheet:', error);
return '';
}
}

// Get all stylesheet links on the page
const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]')) as HTMLLinkElement[];

// Check each stylesheet for Tailwind CSS patterns
for (let link of links) {
if (!link.href) continue; // Skip if no href attribute
const content = await fetchStylesheet(link.href);
// Look for a Tailwind CSS signature pattern
if (content.includes('tailwindcss') || content.includes('@tailwind')) {
return true; // Tailwind CSS pattern found
}
}

return false; // No Tailwind CSS patterns found in any stylesheet
}

async getCSSFramework(): Promise<StyleFramework | undefined> {
try {
if (await this.isTailwindUsed()) {
return StyleFramework.TailwindCSS;
} else {
return StyleFramework.InlineCSS;
}
} catch (error) {
console.error('Error detecting the CSS framework:', error);
return undefined;
}
}
}
14 changes: 7 additions & 7 deletions editor/src/lib/tools/edit/handleEvents.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { addToHistory } from "./history";
import { getDataOnlookComponentId, getDataOnlookId, getUniqueSelector } from "../utilities";
import { EditType, type EditEvent, type ChildVal } from "$shared/models";
import { MessageService, MessageType } from "$shared/message";
import { EditSource } from "$shared/models/editor";
import { getCustomComponentContent } from "$shared/helpers";
import { MessageType } from "$shared/message";
import { EditType, type ChildVal, type EditEvent } from "$shared/models";
import { EditSource } from "$shared/models/editor";
import { sendMessage } from "webext-bridge/window";
import { getDataOnlookComponentId, getDataOnlookId, getUniqueSelector } from "../utilities";
import { addToHistory } from "./history";

const elementSelectorCache: WeakMap<object, string> = new WeakMap(); // Cache for element selectors
const messageService = MessageService.getInstance();

function debounce(func, wait) {
const timeouts = {};
Expand Down Expand Up @@ -103,7 +103,7 @@ export function undebounceHandleEditEvent(param: HandleEditEventParams) {
if (componentId) {
event = updateEventIfStructureChange(param) || event;
}
messageService.publish(MessageType.EDIT_EVENT, event);
sendMessage(MessageType.EDIT_EVENT, event);
}

let debouncedHandleEditEvent = debounce(undebounceHandleEditEvent, 1000);
Expand Down
Loading