@prisma/client#notionSites TypeScript Examples

The following examples show how to use @prisma/client#notionSites. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: SiteCard.tsx    From pagely with MIT License 6 votes vote down vote up
SiteCard: React.FC<{ siteData: notionSites }> = ({ siteData }) => {
  const { siteName, siteDesc, id, ogImageUrl } = siteData;
  return (
    <div className='max-w-[400px] mx-auto'>
      <Link href={`/notion-site/${id}`}>
        <a>
          <div className='mb-8 transition-all duration-500 border border-gray-300 rounded hover:shadow-xl'>
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img
              src={ogImageUrl || '/no-og-image.png'}
              alt={siteName}
              className='object-cover w-full h-32 mx-auto rounded-t'
            />
            <div className='px-3 pt-4 pb-5'>
              <h2 className='text-2xl font-bold'>{siteName}</h2>
              <p className='mt-1 text-base text-gray-600'>
                {truncate(siteDesc, { length: 50 }) ||
                  'No description ¯\\_(ツ)_/¯'}
              </p>
            </div>
          </div>
        </a>
      </Link>
    </div>
  );
}
Example #2
Source File: index.tsx    From pagely with MIT License 5 votes vote down vote up
Page = () => {
  const router = useRouter();
  const { data } = useClerkSWR<notionSites>(
    `/api/getSiteData/notion/?siteId=${router.query.notionId}`
  );

  return (
    <div>
      <SidebarLayout activeTab='setup'>
        <h1 className='text-4xl font-extrabold capitalize'>
          {data?.siteName || 'Just a second...'}
        </h1>
        <p className='mt-4 text-gray-800 font-base'>
          {data?.siteDesc ||
            'Crunching the data for you. Please give a second.'}
        </p>
        <div className='flex flex-wrap mt-8'>
          <a
            href={data?.notionPageUrl}
            target='_blank'
            rel='noopener noreferrer'>
            <div className='inline-block px-3 py-4 my-2 mr-3 transition-all bg-yellow-100 border rounded-md hover:shadow hover:border-yellow-500'>
              <SiNotion className='relative inline-block mx-2 bottom-[2px]' />
              Open in Notion
            </div>
          </a>
          <a
            href={
              'https://developers.google.com/speed/pagespeed/insights/?url=https://' +
              data?.subdomain +
              '.pagely.site'
            }
            target='_blank'
            rel='noopener noreferrer'>
            <div className='inline-block px-3 py-4 my-2 mr-3 transition-all bg-blue-100 border rounded-md hover:shadow hover:border-blue-500'>
              <SiLighthouse className='relative inline-block mx-2 bottom-[2px]' />
              Open Lighthouse score
            </div>
          </a>
          <a
            href={'https://' + data?.subdomain + '.pagely.site'}
            target='_blank'
            rel='noopener noreferrer'>
            <div className='inline-block px-3 py-4 my-2 mr-3 transition-all bg-green-100 border rounded-md hover:shadow hover:border-green-500'>
              <VscGlobe className='relative inline-block mx-2 bottom-[2px]' />
              Open website
            </div>
          </a>
        </div>
      </SidebarLayout>
    </div>
  );
}
Example #3
Source File: TwitterPreview.tsx    From pagely with MIT License 4 votes vote down vote up
TwitterPreview: React.FC<{ data: notionSites }> = ({ data }) => {
  const [isImageLoading, setIsImageLoading] = useState<boolean>(true);
  const { firstName, primaryEmailAddress } = useUser();
  return (
    <div>
      <div className='w-full max-w-xl px-5 py-3 border border-gray-300 rounded-2xl'>
        <div className='flex'>
          <div className='mr-2 w-14'>
            <Image
              src={Elon}
              alt='Elon'
              className='object-cover rounded-full'
            />
          </div>
          <div>
            <div className='flex space-x-1'>
              <span className='font-bold'>Elon Musk</span>
              <span className='text-twitter-blue' title='Verified account'>
                <svg
                  className='w-6 h-6'
                  fill='currentColor'
                  viewBox='0 0 24 24'
                  aria-label='Verified account'>
                  <g>
                    <path d='M22.5 12.5c0-1.58-.875-2.95-2.148-3.6.154-.435.238-.905.238-1.4 0-2.21-1.71-3.998-3.818-3.998-.47 0-.92.084-1.336.25C14.818 2.415 13.51 1.5 12 1.5s-2.816.917-3.437 2.25c-.415-.165-.866-.25-1.336-.25-2.11 0-3.818 1.79-3.818 4 0 .494.083.964.237 1.4-1.272.65-2.147 2.018-2.147 3.6 0 1.495.782 2.798 1.942 3.486-.02.17-.032.34-.032.514 0 2.21 1.708 4 3.818 4 .47 0 .92-.086 1.335-.25.62 1.334 1.926 2.25 3.437 2.25 1.512 0 2.818-.916 3.437-2.25.415.163.865.248 1.336.248 2.11 0 3.818-1.79 3.818-4 0-.174-.012-.344-.033-.513 1.158-.687 1.943-1.99 1.943-3.484zm-6.616-3.334l-4.334 6.5c-.145.217-.382.334-.625.334-.143 0-.288-.04-.416-.126l-.115-.094-2.415-2.415c-.293-.293-.293-.768 0-1.06s.768-.294 1.06 0l1.77 1.767 3.825-5.74c.23-.345.696-.436 1.04-.207.346.23.44.696.21 1.04z' />
                  </g>
                </svg>
              </span>
            </div>
            <div className='leading-4 text-gray-500'>@elonmusk</div>
          </div>
          <div className='ml-auto text-twitter-blue'>
            <svg viewBox='0 0 24 24' fill='currentColor' className='w-6 h-6'>
              <g>
                <path d='M23.643 4.937c-.835.37-1.732.62-2.675.733.962-.576 1.7-1.49 2.048-2.578-.9.534-1.897.922-2.958 1.13-.85-.904-2.06-1.47-3.4-1.47-2.572 0-4.658 2.086-4.658 4.66 0 .364.042.718.12 1.06-3.873-.195-7.304-2.05-9.602-4.868-.4.69-.63 1.49-.63 2.342 0 1.616.823 3.043 2.072 3.878-.764-.025-1.482-.234-2.11-.583v.06c0 2.257 1.605 4.14 3.737 4.568-.392.106-.803.162-1.227.162-.3 0-.593-.028-.877-.082.593 1.85 2.313 3.198 4.352 3.234-1.595 1.25-3.604 1.995-5.786 1.995-.376 0-.747-.022-1.112-.065 2.062 1.323 4.51 2.093 7.14 2.093 8.57 0 13.255-7.098 13.255-13.254 0-.2-.005-.402-.014-.602.91-.658 1.7-1.477 2.323-2.41z' />
              </g>
            </svg>
          </div>
        </div>
        <div className='py-3'>
          <p className='text-lg'>
            Check this website out. Made by{' '}
            {firstName || primaryEmailAddress.emailAddress.split('@')[0]}
          </p>
          <p className='text-lg text-twitter-blue'>
            https://{data?.subdomain}.pagely.site
          </p>
          <div className='my-2 w-[90%] hover:bg-gray-100 cursor-pointer'>
            <div>
              {data?.ogImageUrl !== 'https://no-og.image' && (
                <>
                  {/* eslint-disable-next-line @next/next/no-img-element */}
                  <img
                    src={
                      data?.ogImageUrl ||
                      'https://ogimage.glitch.me/i/' +
                        encodeURIComponent(data?.siteName)
                    }
                    alt={data?.siteName}
                    className='rounded-t-xl'
                    onLoad={() => setIsImageLoading(false)}
                  />
                  {isImageLoading && (
                    <Skeleton
                      height='240px'
                      className='!rounded-t-xl w-[90%]'
                    />
                  )}
                </>
              )}
              <div
                className={`px-2 py-3 border border-gray-400 bg-gray-50/10 ${
                  data?.ogImageUrl == 'https://no-og.image'
                    ? 'rounded-md'
                    : 'rounded-b-xl'
                }`}>
                <h3 className='font-bold text-gray-600'>
                  {data?.siteName || 'OG title loading'}
                </h3>
                <div className='text-base text-gray-400'>
                  {data?.siteDesc || 'OG description loading'}
                </div>
              </div>
            </div>
          </div>
          <div className='flex'>
            <p className='pt-1 text-gray-500'>1:57 PM · Feb 4, 2021</p>
            <svg
              className='w-6 h-6 ml-auto text-gray-500'
              fill='currentColor'
              viewBox='0 0 24 24'>
              <g>
                <path d='M12 18.042c-.553 0-1-.447-1-1v-5.5c0-.553.447-1 1-1s1 .447 1 1v5.5c0 .553-.447 1-1 1z' />
                <circle cx={12} cy='8.042' r='1.25' />
                <path d='M12 22.75C6.072 22.75 1.25 17.928 1.25 12S6.072 1.25 12 1.25 22.75 6.072 22.75 12 17.928 22.75 12 22.75zm0-20C6.9 2.75 2.75 6.9 2.75 12S6.9 21.25 12 21.25s9.25-4.15 9.25-9.25S17.1 2.75 12 2.75z' />
              </g>
            </svg>
          </div>
        </div>
        <div className='flex pt-3 space-x-5 text-gray-500 border-t border-gray-300'>
          <div className='flex space-x-2'>
            <svg
              viewBox='0 0 24 24'
              fill='currentColor'
              className='w-6 h-6'
              style={{}}>
              <g>
                <path d='M12 21.638h-.014C9.403 21.59 1.95 14.856 1.95 8.478c0-3.064 2.525-5.754 5.403-5.754 2.29 0 3.83 1.58 4.646 2.73.814-1.148 2.354-2.73 4.645-2.73 2.88 0 5.404 2.69 5.404 5.755 0 6.376-7.454 13.11-10.037 13.157H12zM7.354 4.225c-2.08 0-3.903 1.988-3.903 4.255 0 5.74 7.034 11.596 8.55 11.658 1.518-.062 8.55-5.917 8.55-11.658 0-2.267-1.823-4.255-3.903-4.255-2.528 0-3.94 2.936-3.952 2.965-.23.562-1.156.562-1.387 0-.014-.03-1.425-2.965-3.954-2.965z' />
              </g>
            </svg>
            <span>783.9k</span>
          </div>
          <div className='flex space-x-2'>
            <svg viewBox='0 0 24 24' fill='currentColor' className='w-6 h-6'>
              <g>
                <path d='M14.046 2.242l-4.148-.01h-.002c-4.374 0-7.8 3.427-7.8 7.802 0 4.098 3.186 7.206 7.465 7.37v3.828c0 .108.044.286.12.403.142.225.384.347.632.347.138 0 .277-.038.402-.118.264-.168 6.473-4.14 8.088-5.506 1.902-1.61 3.04-3.97 3.043-6.312v-.017c-.006-4.367-3.43-7.787-7.8-7.788zm3.787 12.972c-1.134.96-4.862 3.405-6.772 4.643V16.67c0-.414-.335-.75-.75-.75h-.396c-3.66 0-6.318-2.476-6.318-5.886 0-3.534 2.768-6.302 6.3-6.302l4.147.01h.002c3.532 0 6.3 2.766 6.302 6.296-.003 1.91-.942 3.844-2.514 5.176z' />
              </g>
            </svg>
            <span>139.7k</span>
          </div>
          <div className='hidden space-x-2 sm:flex'>
            <svg
              viewBox='0 0 24 24'
              fill='currentColor'
              className='w-6 h-6'
              style={{}}>
              <g>
                <path d='M11.96 14.945c-.067 0-.136-.01-.203-.027-1.13-.318-2.097-.986-2.795-1.932-.832-1.125-1.176-2.508-.968-3.893s.942-2.605 2.068-3.438l3.53-2.608c2.322-1.716 5.61-1.224 7.33 1.1.83 1.127 1.175 2.51.967 3.895s-.943 2.605-2.07 3.438l-1.48 1.094c-.333.246-.804.175-1.05-.158-.246-.334-.176-.804.158-1.05l1.48-1.095c.803-.592 1.327-1.463 1.476-2.45.148-.988-.098-1.975-.69-2.778-1.225-1.656-3.572-2.01-5.23-.784l-3.53 2.608c-.802.593-1.326 1.464-1.475 2.45-.15.99.097 1.975.69 2.778.498.675 1.187 1.15 1.992 1.377.4.114.633.528.52.928-.092.33-.394.547-.722.547z' />
                <path d='M7.27 22.054c-1.61 0-3.197-.735-4.225-2.125-.832-1.127-1.176-2.51-.968-3.894s.943-2.605 2.07-3.438l1.478-1.094c.334-.245.805-.175 1.05.158s.177.804-.157 1.05l-1.48 1.095c-.803.593-1.326 1.464-1.475 2.45-.148.99.097 1.975.69 2.778 1.225 1.657 3.57 2.01 5.23.785l3.528-2.608c1.658-1.225 2.01-3.57.785-5.23-.498-.674-1.187-1.15-1.992-1.376-.4-.113-.633-.527-.52-.927.112-.4.528-.63.926-.522 1.13.318 2.096.986 2.794 1.932 1.717 2.324 1.224 5.612-1.1 7.33l-3.53 2.608c-.933.693-2.023 1.026-3.105 1.026z' />
              </g>
            </svg>
            <span>Copy link to tweet</span>
          </div>
        </div>
      </div>
    </div>
  );
}
Example #4
Source File: SidebarLayout.tsx    From pagely with MIT License 4 votes vote down vote up
SidebarLayout: React.FC<{
  activeTab: 'code' | 'setup' | 'pages' | 'settings' | 'seo';
  title?: string;
}> = ({ activeTab, title, ...props }) => {
  const { emailAddresses, profileImageUrl, fullName, firstName } = useUser();
  const { signOut } = useClerk();

  const router = useRouter();
  const { data } = useClerkSWR<notionSites>(
    `/api/getSiteData/notion/?siteId=${router.query.notionId}`
  );
  return (
    <div>
      <div className='block lg:hidden'>
        <DashboardNav />
        <Head>
          <title>
            {title ||
              data?.siteName +
                ' - ' +
                activeTab.charAt(0).toUpperCase() +
                activeTab.slice(1) +
                ' | ' +
                'Pagely'}
          </title>
        </Head>
      </div>
      <div className='lg:flex'>
        {/* <div className='sticky top-0 overflow-y-hidden'> */}
        <div
          style={{ position: 'sticky' }}
          className='absolute top-0 h-screen left-0 px-10 py-5 bg-gray-50 w-[20vw] border-r hidden flex-col justify-between lg:flex'>
          <div>
            <Link href='/dashboard'>
              <a>
                <small className='text-gray-700 hover:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                  {' '}
                  {'<'}- Go back
                </small>
              </a>
            </Link>
            <ul className='mt-10'>
              <li
                className={`my-2 rounded ${
                  activeTab === 'setup' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={'/notion-site/' + data?.id}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <GoInbox className='relative inline-block bottom-[2px]' />{' '}
                    Setup
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'seo' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={`/notion-site/${data?.id}/seo`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <BiSearchAlt className='relative inline-block bottom-[2px]' />{' '}
                    SEO
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'code' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={`/notion-site/${data?.id}/code`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <BiCode className='relative inline-block bottom-[2px]' />{' '}
                    Code injection
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'pages' ? ' bg-gray-200' : ' hover:bg-gray-300'
                }`}>
                <Link href={`/notion-site/${data?.id}/pages`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <HiOutlineNewspaper className='relative inline-block bottom-[2px]' />{' '}
                    Pages
                  </a>
                </Link>
              </li>
              <li
                className={`my-2 rounded ${
                  activeTab === 'settings'
                    ? ' bg-gray-200'
                    : ' hover:bg-gray-300'
                }`}>
                <Link href={`/notion-site/${data?.id}/settings`}>
                  <a className='block px-3 py-2 my-2 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-700'>
                    {' '}
                    <FiSettings className='relative inline-block bottom-[2px]' />{' '}
                    Settings
                  </a>
                </Link>
              </li>
            </ul>
          </div>
          <ProfileDropdown
            emailAddresses={emailAddresses}
            profileImageUrl={profileImageUrl}
            fullName={fullName}
            firstName={firstName}
            signOut={signOut}
          />
        </div>
        <div className='mx-10 mt-20'>{props.children}</div>
      </div>
      <Toaster />
    </div>
  );
}
Example #5
Source File: dashboard.tsx    From pagely with MIT License 4 votes vote down vote up
Dashboard = () => {
  const { data: notionSites, error } = useClerkSWR<notionSites[]>(
    '/api/getAllSites/notion'
  );
  const { data: githubSites, error: errorFetchingGithubSites } = useClerkSWR<
    ghSites[]
  >('/api/getAllSites/github');
  const { data: showcaseWebsites } = useClerkSWR<ShowcaseWebsites[]>(
    '/api/getShowcaseWebsites'
  );
  return (
    <MainLayout>
      <div>
        <div className='max-w-5xl mx-auto'>
          <h1 className='text-4xl font-bold text-center lg:text-left md:relative lg:left-14'>
            Your websites
          </h1>
          <div className='flex'>
            <div
              className='flex-1 mr-2 mt-10 h-[70vh] overflow-y-scroll pb-5'
              id='websites'>
              <div>
                <h3 className='mb-5 text-lg font-medium lg:text-left md:relative lg:left-14'>
                  Notion websites
                </h3>
                {notionSites?.map((site) => (
                  // @ts-ignore
                  <SiteCard key={site.id} siteData={site} />
                ))}
                {error && (
                  <h1>
                    Your Notion sites could not be fetched. Please reload and
                    try again
                  </h1>
                )}
                {!error && !notionSites && (
                  <Skeleton
                    width='384px'
                    height='200px'
                    count={3}
                    className='!block mb-8 mx-auto'
                  />
                )}
              </div>
              <hr className='w-[80%] my-5 text-gray-300 mx-auto' />
              <div className='mb-5'>
                <h3 className='mb-5 text-lg font-medium lg:text-left md:relative lg:left-14'>
                  GitHub websites
                </h3>
                {githubSites?.map((site) => (
                  // @ts-ignore
                  <GitHubSiteCard key={site.id} siteData={site} />
                  // <p key={site.id}>{JSON.stringify(site, null, 2)}</p>
                ))}
                {errorFetchingGithubSites && (
                  <h1>
                    Your GitHub sites could not be fetched. Please reload and
                    try again
                  </h1>
                )}
                {!errorFetchingGithubSites && !githubSites && (
                  <Skeleton
                    width='384px'
                    height='200px'
                    count={3}
                    className='!block mb-8 mx-auto'
                  />
                )}
              </div>
            </div>
            <div className='sticky top-0 flex-1 hidden mt-10 lg:block'>
              <div className='text-center transition-all bg-blue-100 border border-blue-300 rounded shadow-sm hover:bg-blue-200'>
                <Link href='/new'>
                  <a className='block px-4 py-3 text-lg -mt-[50px]'>
                    <HiOutlinePlusCircle className='relative inline-block w-8 h-8 mr-1 text-gray-600 bottom-[2px]' />
                    Create new website
                  </a>
                </Link>
              </div>
              <hr className='my-5 w-[80%] mx-auto text-gray-300' />
              <div className='mt-4 text-center'>
                <h3 className='text-2xl font-medium'>
                  Some awesome websites made with Pagely
                </h3>
                <div
                  className='flex flex-wrap px-2 mt-3 overflow-y-auto h-[50vh] pb-5'
                  id='showcase-websites'>
                  {showcaseWebsites?.map((site) => {
                    return (
                      <div
                        key={site.siteName}
                        style={{ zoom: '0.6' }}
                        className='mr-1'>
                        <a
                          href={'https://' + site.subdomain + '.pagely.site'}
                          target='_blank'
                          rel='noopener noreferrer'>
                          <div className='max-w-sm px-3 mx-auto text-center transition-all duration-500 rounded-lg py-7 hover:border border-bluegray-200 hover:shadow-lg group'>
                            {(
                              // eslint-disable-next-line @next/next/no-img-element
                              <img
                                src={site.ogImageUrl || '/no-og-image.png'}
                                alt={site.siteName}
                                className='w-[80%] mx-auto mb-4 rounded-lg group-hover:scale-105 object-cover transform transition-all duration-500 border border-gray-300'
                              />
                            ) || (
                              <Skeleton className='w-[80%] mx-auto mb-4 rounded-lg group-hover:scale-105 object-cover transform transition-all duration-500 border border-gray-300' />
                            )}
                            <h3 className='text-2xl font-medium'>
                              {truncate(site.siteName, { length: 30 })}
                            </h3>
                          </div>
                        </a>
                      </div>
                    );
                  })}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <style jsx>{`
        #showcase-websites::-webkit-scrollbar {
          display: none;
        }
        #showcase-websites {
          -ms-overflow-style: none;
        }
        #websites::-webkit-scrollbar {
          display: none;
        }
        #websites {
          -ms-overflow-style: none;
        }
      `}</style>
    </MainLayout>
  );
}
Example #6
Source File: code.tsx    From pagely with MIT License 4 votes vote down vote up
Page = () => {
  const router = useRouter();
  const { data } = useClerkSWR<notionSites>(
    `/api/getSiteData/notion/?siteId=${router.query.notionId}`
  );

  const [css, setCss] = useState<string>(data?.customCss);
  const [head, setHead] = useState<string>(data?.customHead);
  let [isOpen, setIsOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const urlWithSession = useUserWithSession('/api/updateSiteData/notion/code');

  function closeModal() {
    setIsOpen(false);
  }

  function openModal() {
    setIsOpen(true);
  }

  useEffect(() => {
    window.addEventListener('keydown', (e) => {
      if (e.metaKey && e.key === 's') {
        e.preventDefault();
        document.getElementById('update-custom-code-btn').click();
      }
    });
  }, []);

  return (
    <div>
      <div>
        <SidebarLayout activeTab='code'>
          <h1 className='text-4xl font-extrabold'>Code Injection</h1>
          <p className='mt-4 text-gray-800 font-base'>
            {data?.siteName || 'Just a second...'}
          </p>
          <div className='my-3'>
            <button
              onClick={openModal}
              className='px-2 py-1 text-green-600 border border-green-500 rounded shadow bg-green-50 hover:bg-green-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-green-200'>
              Open styling tools
            </button>
            <p className='my-1 text-sm text-gray-500'>
              PROTIP: Use the{' '}
              <a
                target='_blank'
                rel='noopener noreferrer'
                className='underline'
                href='https://chrome.google.com/webstore/detail/stylebot/oiaejidbmkiecgbjeifoejpgmdaleoha'>
                `Stylebot`
              </a>{' '}
              extension to style your website without code. View demo at{' '}
              <a
                className='underline'
                target='_blank'
                rel='noopener noreferrer'
                href={process.env.NEXT_PUBLIC_LOOM_VIDEO_URL}>
                here
              </a>
              .
            </p>
          </div>
          <div className='mt-8'>
            <p className='my-3 font-mono text-xl font-bold text-gray-500'>{`<style>`}</p>
            <TextareaAutosize
              spellCheck={false}
              value={css}
              onChange={(e) => setCss(e.target.value)}
              className='w-[70vw] py-5 font-mono border text-sm min-h-[100px] border-gray-600 rounded-md shadow-sm block text-gray-500 focus:outline-none focus:border-gray-700 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500'
              onKeyDown={(e) => handleHotkeys(e)}
            />
            <p className='my-3 font-mono text-xl font-bold text-gray-500'>{`</style>`}</p>
          </div>
          <hr className='my-10 text-gray-300' />
          <div className='mt-8'>
            <p className='my-3 font-mono text-xl font-bold text-gray-500'>{`<head>`}</p>
            <TextareaAutosize
              spellCheck={false}
              value={head}
              onChange={(e) => setHead(e.target.value)}
              className='w-[70vw] py-5 font-mono border text-sm min-h-[100px] border-gray-600 rounded-md shadow-sm block text-gray-500 focus:outline-none focus:border-gray-700 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-gray-500'
            />
            <p className='my-3 font-mono text-xl font-bold text-gray-500'>{`</head>`}</p>
            <div className='my-10'>
              <button
                id='update-custom-code-btn'
                onClick={() => {
                  setIsLoading(true);
                  axios
                    .post(urlWithSession, {
                      customCss: css,
                      customHead: head,
                      siteId: data.id,
                    })
                    .then((res) => {
                      console.log(res);
                      toast.success('Successfully updated site code.', {
                        duration: 5000,
                      });
                      setIsLoading(false);
                    });
                }}
                className={`h-10 px-3 mb-10 bg-gray-800 rounded shadow-md text-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-800 hover:bg-gray-700 ${
                  isLoading && 'opacity-50 cursor-wait'
                }`}>
                {/* className={`h-10 px-3 shadow-md bg-gray-800 rounded text-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-800 hover:bg-gray-700 ${
                  isLoading && 'opacity-60 cursor-pointer pointer-events-none'
                }`}> */}
                Update Custom Code
              </button>
              <p className='mt-3 text-base text-gray-600'>
                You can press <b>Cmd + S</b> to save the code too ✌️
              </p>
            </div>
          </div>
        </SidebarLayout>
        <Transition appear show={isOpen} as={Fragment}>
          <Dialog
            as='div'
            className='fixed inset-0 z-10 overflow-y-auto'
            onClose={closeModal}>
            <div className='min-h-screen px-4 text-center'>
              <Transition.Child
                as={Fragment}
                enter='ease-out duration-300'
                enterFrom='opacity-0'
                enterTo='opacity-100'
                leave='ease-in duration-200'
                leaveFrom='opacity-100'
                leaveTo='opacity-0'>
                <Dialog.Overlay className='fixed inset-0 backdrop-filter backdrop-blur-sm bg-white/40' />
              </Transition.Child>

              {/* This element is to trick the browser into centering the modal contents. */}
              <span
                className='inline-block h-screen align-middle'
                aria-hidden='true'>
                &#8203;
              </span>
              <Transition.Child
                as={Fragment}
                enter='ease-out duration-300'
                enterFrom='opacity-0 scale-95'
                enterTo='opacity-100 scale-100'
                leave='ease-in duration-200'
                leaveFrom='opacity-100 scale-100'
                leaveTo='opacity-0 scale-95'>
                <div className='inline-block w-full max-w-3xl p-6 my-8 overflow-hidden text-left align-middle transition-all transform bg-white border rounded-md shadow-xl border-gray-500/40'>
                  <Dialog.Title
                    as='h3'
                    className='text-lg font-medium leading-6 text-gray-900'>
                    CSS Utilities ?
                  </Dialog.Title>
                  <div className='mt-2 mb-10'>
                    <p className='text-sm text-gray-500'>
                      A tiny set of utilities to help you style your app and
                      make it look great. Many more utilities are coming soon.
                    </p>
                    <hr className='w-full mx-auto my-5 text-gray-200' />
                    <Utility />
                  </div>

                  <div className='mt-4'>
                    <button
                      type='button'
                      className='inline-flex justify-center px-4 py-1 text-sm font-medium text-blue-900 bg-blue-100 border border-blue-500 rounded-md hover:bg-blue-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-500'
                      onClick={openModal}>
                      Thanks!
                    </button>
                  </div>
                </div>
              </Transition.Child>
            </div>
          </Dialog>
        </Transition>
      </div>
    </div>
  );
}
Example #7
Source File: seo.tsx    From pagely with MIT License 4 votes vote down vote up
Page = () => {
  const router = useRouter();
  const { data, mutate } = useClerkSWR<notionSites>(
    `/api/getSiteData/notion/?siteId=${router.query.notionId}`
  );

  const [isImageLoading, setIsImageLoading] = useState<boolean>(true);
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const updateUrlWithSession = useUrlWithSession(
    '/api/updateSiteData/notion/seo'
  );
  const {
    handleSubmit,
    register,
    setValue,
    formState: { errors },
    control,
  } = useForm<NotionSeoSettings>({
    resolver: zodResolver(notionPageSeoSchema),
    defaultValues: {
      ogImageUrl: data?.ogImageUrl,
      siteName: data?.siteName,
      siteDesc: data?.siteDesc,
    },
  });

  const updateSeoData = (formData) => {
    setIsLoading(true);
    console.log('updating SEO');
    const { ogImageUrl, siteName, siteDesc } = formData;
    console.log('values obtained' + JSON.stringify(formData));
    console.log('about to post');
    axios
      .post(updateUrlWithSession, {
        siteId: data?.id,
        ogImageUrl: ogImageUrl,
        siteName: siteName,
        siteDesc: siteDesc,
      })
      .then(() => {
        console.log('done updating');
        setIsLoading(false);
        toast.success('SEO settings updated.');
        mutate(
          {
            ...data,
            ogImageUrl: ogImageUrl,
            siteName: siteName,
            siteDesc: siteDesc,
          },
          false
        );
        console.log('done');
      })
      .catch((err) => {
        console.log('caught error');

        setIsLoading(false);
        toast.error('Failed to update SEO settings\n' + err.message, {
          duration: 5000,
        });
      });
    console.log('done posting');
  };

  return (
    <div>
      {process.env.NODE_ENV !== 'production' && (
        <DevTool control={control} placement='top-right' />
      )}
      <SidebarLayout activeTab='seo'>
        <h1 className='text-4xl font-extrabold'>SEO Settings</h1>
        <p className='mt-4 text-gray-800 font-base'>
          {data?.siteName || 'Just a second...'}
        </p>
        <div className='my-5 mt-10'>
          <h2 className='mb-5 text-2xl font-bold'>Twitter Preview</h2>
          <TwitterPreview data={data} />
        </div>
        <form
          id='notion-seo-form'
          className='mt-8'
          onSubmit={(e) => {
            e.preventDefault();
            handleSubmit(updateSeoData)();
          }}>
          <hr className='my-10 text-gray-400' />
          <h2 className='mb-5 text-2xl font-bold'>OG Image</h2>
          <div className='max-w-[600px] max-h-[315px]'>
            {data?.ogImageUrl === 'https://no-og.image' ? (
              <Image
                alt='No OG Image'
                src={NoOgImage}
                onLoad={() => setIsImageLoading(false)}
                className='border border-gray-400 rounded'
              />
            ) : (
              // eslint-disable-next-line @next/next/no-img-element
              <img
                src={
                  data?.ogImageUrl ||
                  'https://ogimage.glitch.me/i/' +
                    encodeURIComponent(data?.siteName)
                }
                alt={data?.siteName}
                className='object-cover rounded-md'
                onLoad={() => setIsImageLoading(false)}
              />
            )}
            {isImageLoading && <Skeleton width='600px' height='315px' />}
          </div>
          <div>
            <label className='block mt-3'>
              <span className='mt-1 text-sm text-gray-600'>
                If left blank, the OG Image will be automatically generated from
                site name and Notion page&apos;s title!!
              </span>
              <InfoPopover content='This is the image that will appear in the OG cards and Twitter cards. 1200x630 is the recommended dimension for the OG image. This can boost your conversion rate by upto 2 times!!'>
                <Image
                  placeholder='blur'
                  src={OgImage}
                  alt=''
                  className='inline-block w-full rounded'
                />
              </InfoPopover>
              <div className='flex items-center'>
                <input
                  type='text'
                  className='inline-block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200'
                  placeholder='https://picsum.photos/1200/630'
                  {...register('ogImageUrl')}
                />
              </div>
              <p className='mt-2 text-sm text-red-500'>
                {errors.ogImageUrl && errors.ogImageUrl.message}
              </p>
              <div>
                <div>
                  <div className='inline-block px-2 py-px mt-2 text-sm text-gray-700 border border-gray-200 rounded cursor-pointer bg-gray-50 hover:bg-gray-100'>
                    <Dropzone
                      onDrop={(files) => {
                        uploadImage(files, setValue);
                      }}>
                      {({ getRootProps, getInputProps }) => (
                        <div {...getRootProps()}>
                          <input type='file' {...getInputProps()} />
                          <BiCloudUpload className='relative inline-block w-5 h-5 bottom-px' />{' '}
                          Upload image
                        </div>
                      )}
                    </Dropzone>
                  </div>
                  <p className='mt-1 text-sm text-gray-500'>
                    Or just drag &apos;n&apos; drop an image over the button !
                  </p>
                </div>
              </div>
            </label>
          </div>

          <hr className='my-10 text-gray-200' />

          <div>
            <h2 className='mb-5 text-2xl font-bold'>OG Title</h2>
            <p className='text-gray-800'>{data?.siteName}</p>
            <div>
              <label className='block mt-3'>
                <span className='mt-1 text-sm text-gray-600'>
                  This name will be used for generating OG title
                </span>
                <InfoPopover content='This is the name of your website. It is also the title in Twitter cards and OG cards.'>
                  <Image
                    placeholder='blur'
                    src={TweetTitleImage}
                    alt=''
                    className='inline-block w-full rounded'
                  />
                </InfoPopover>
                <div className='flex items-center'>
                  <input
                    type='text'
                    className='inline-block w-full mt-1 mr-1 border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200'
                    placeholder='Blog - Elon'
                    {...register('siteName')}
                  />
                </div>
                <p className='mt-2 text-sm text-red-500'>
                  {errors.siteName && errors.siteName.message}
                </p>
              </label>
            </div>
          </div>
          <hr className='my-10 text-gray-200' />

          <div className='mb-5'>
            <h2 className='mb-5 text-2xl font-bold'>OG Description</h2>
            <p className='text-gray-800'>{data?.siteDesc}</p>
            <div>
              <label className='block mt-3'>
                <span className='mt-1 text-sm text-gray-600'>
                  This name will be used for generating OG and Twitter
                  descriptions
                </span>

                <InfoPopover content='This is the description of your website. It is also the description in Twitter cards and OG cards.'>
                  <Image
                    placeholder='blur'
                    src={TweetDescImage}
                    alt=''
                    className='inline-block w-full rounded'
                  />
                </InfoPopover>
                <textarea
                  className='block w-full mt-1 text-base border-gray-300 rounded-md shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50'
                  rows={4}
                  placeholder='Read my blog to...'
                  {...register('siteDesc')}
                />
                <p className='mt-2 text-sm text-red-500'>
                  {errors.siteDesc && errors.siteDesc.message}
                </p>
              </label>
            </div>
          </div>
          <div>
            <button
              type='submit'
              form='notion-seo-form'
              className={`h-10 px-3 mb-10 bg-gray-800 rounded shadow-md text-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-800 hover:bg-gray-700 ${
                isLoading && 'opacity-50 cursor-wait'
              }`}>
              {isLoading ? 'Saving changes...' : 'Save changes'}
            </button>
          </div>
        </form>
      </SidebarLayout>
    </div>
  );
}
Example #8
Source File: settings.tsx    From pagely with MIT License 4 votes vote down vote up
Page = () => {
  const router = useRouter();
  const { data } = useClerkSWR<notionSites>(
    `/api/getSiteData/notion/?siteId=${router.query.notionId}`
  );

  const urlWithSession = useUserWithSession(
    '/api/updateSiteData/notion/showcase'
  );
  const deleteUrlWithSession = useUserWithSession('/api/deleteSite/notion');

  const [enabled, setEnabled] = useState(data?.inShowcase);
  const [isLoading, setIsLoading] = useState(false);
  const [isOpen, setIsOpen] = useState(false);

  function closeModal() {
    setIsOpen(false);
  }

  function openModal() {
    setIsOpen(true);
  }

  return (
    <div>
      <div>
        <SidebarLayout activeTab='settings'>
          <h1 className='text-4xl font-extrabold'>Settings</h1>
          <p className='mt-4 text-gray-800 font-base'>
            {data?.siteName || 'Just a second...'}
          </p>
          <div className='mt-8'>
            <h2 className='text-2xl font-bold'>Showcase Settings</h2>
            <div className='flex items-center my-5'>
              <span className='inline-block mr-2'>
                I prefer not to display{' '}
                <strong title={data?.siteName}>
                  {truncate(data?.siteName, {
                    length: 15,
                  })}
                </strong>{' '}
                in showcase
              </span>
              <Switch
                checked={enabled}
                onChange={setEnabled}
                style={{ zoom: 0.5 }}
                className={`${enabled ? 'bg-gray-900' : 'bg-gray-700'}
          relative inline-flex flex-shrink-0 h-[38px] w-[74px] border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus-visible:ring-2  focus-visible:ring-white focus-visible:ring-opacity-75`}>
                <span className='sr-only'>Use setting</span>
                <span
                  aria-hidden='true'
                  className={`${enabled ? 'translate-x-9' : 'translate-x-0'}
            pointer-events-none inline-block h-[34px] w-[34px] rounded-full bg-white shadow-lg transform ring-0 transition ease-in-out duration-200`}
                />
              </Switch>
              <span className='inline-block ml-2'>
                Display{' '}
                <strong title={data?.siteName}>
                  {truncate(data?.siteName, {
                    length: 15,
                  })}
                </strong>{' '}
                in{' '}
                <Link href='/showcase'>
                  <a className='text-blue-500 hover:underline'>Showcase</a>
                </Link>
              </span>
            </div>
            <button
              onClick={() => {
                setIsLoading(true);
                axios
                  .post(urlWithSession, {
                    inShowcase: enabled,
                    siteId: data.id,
                  })
                  .then((res) => {
                    console.log(res);
                    toast.success(
                      enabled
                        ? `Yay ?, ${data?.siteName} will be displayed in showcase soon.`
                        : `${data?.siteName} will be removed showcase soon.`,
                      {
                        duration: 5000,
                      }
                    );
                    setIsLoading(false);
                  });
              }}
              className={`h-10 px-3 mb-10 bg-gray-800 rounded shadow-md text-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-800 hover:bg-gray-700 ${
                isLoading && 'opacity-50 cursor-wait'
              }`}>
              Update Showcase Settings
            </button>
          </div>
          <hr className='w-[70vw] my-3 text-gray-200' />
          <div className='mt-8'>
            <h2 className='text-2xl font-bold'>Password protection</h2>
            {data?.isPasswordProtected ? (
              <div>
                <div className='flex items-center my-5'>
                  <span className='inline-block'>
                    <strong>{data?.siteName}</strong> has already been password
                    protected
                  </span>
                </div>
                <button className='h-10 px-3 mb-10 bg-gray-800 rounded shadow-md text-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-800 hover:bg-gray-700'>
                  <a
                    href='https://staticshield.vercel.app/dashboard'
                    target='_blank'
                    rel='noopener noreferrer'>
                    View details
                  </a>
                </button>
              </div>
            ) : (
              <div>
                <div className='flex items-center my-5'>
                  <span className='inline-block'>
                    Password protect <strong>{data?.siteName}</strong>
                  </span>
                </div>
                <button
                  onClick={() => {
                    window.open(
                      `https://staticshield.vercel.app/new/?name=${data?.siteName}&desc=${data?.siteDesc}&url=${data?.subdomain}.pagely.site&id=${data?.id}`,
                      '_blank'
                    );
                  }}
                  className={`mb-10 h-10 inline-flex items-center px-3 bg-gray-800 rounded shadow-md text-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-800 hover:bg-gray-700`}>
                  Password protect{' '}
                  <strong className='mx-1'>{data?.siteName}</strong> with{' '}
                  <span className='inline-flex !items-center justify-center p-1 mx-1 bg-white rounded'>
                    <Image
                      src='/staticshield.png'
                      alt=''
                      width='20'
                      height='20'
                      // className='block mt-2'
                    />
                  </span>
                  StaticShield
                </button>
              </div>
            )}
          </div>
          <hr className='w-[70vw] my-3 text-gray-200' />
          <div className='mt-8'>
            <h2 className='text-2xl font-bold text-red-500'>Danger Zone</h2>
            <div className='mt-5'>
              <button
                onClick={openModal}
                className='h-10 px-3 mb-10 bg-red-600 rounded shadow-md text-red-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-800 hover:bg-red-400'>
                {/* <button className='px-2 py-1 text-red-600 border border-red-500 rounded shadow bg-red-50 hover:bg-red-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-red-200'> */}
                Delete <strong>{data?.siteName}</strong>
              </button>
            </div>
          </div>
        </SidebarLayout>
        <Transition appear show={isOpen} as={Fragment}>
          <Dialog
            as='div'
            className='fixed inset-0 z-10 overflow-y-auto'
            onClose={closeModal}>
            <div className='min-h-screen px-4 text-center'>
              <Transition.Child
                as={Fragment}
                enter='ease-out duration-300'
                enterFrom='opacity-0'
                enterTo='opacity-100'
                leave='ease-in duration-200'
                leaveFrom='opacity-100'
                leaveTo='opacity-0'>
                <Dialog.Overlay className='fixed inset-0 backdrop-filter backdrop-blur-sm bg-white/40' />
              </Transition.Child>

              {/* This element is to trick the browser into centering the modal contents. */}
              <span
                className='inline-block h-screen align-middle'
                aria-hidden='true'>
                &#8203;
              </span>
              <Transition.Child
                as={Fragment}
                enter='ease-out duration-300'
                enterFrom='opacity-0 scale-95'
                enterTo='opacity-100 scale-100'
                leave='ease-in duration-200'
                leaveFrom='opacity-100 scale-100'
                leaveTo='opacity-0 scale-95'>
                <div className='inline-block w-full max-w-lg p-6 my-8 overflow-hidden text-left align-middle transition-all transform bg-white border rounded-md shadow-xl border-gray-500/40'>
                  <Dialog.Title
                    as='h3'
                    className='text-lg font-medium leading-6 text-red-700'>
                    Are you sure that you want to delete{' '}
                    <strong>{data?.siteName}</strong>?
                  </Dialog.Title>
                  <div className='mt-2 mb-10'>
                    <p className='text-sm text-gray-500'>
                      Proceed with caution. This action cannot be reversed.
                    </p>
                  </div>

                  <div className='mt-4'>
                    <button
                      type='button'
                      className='inline-flex justify-center px-4 py-1 mr-2 text-sm font-medium text-blue-900 bg-blue-100 border border-blue-500 rounded-md hover:bg-blue-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-500'
                      onClick={closeModal}>
                      Cancel
                    </button>
                    <button
                      type='button'
                      className='inline-flex justify-center px-4 py-1 text-sm font-medium text-red-900 bg-red-100 border border-red-500 rounded-md hover:bg-red-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-red-500'
                      onClick={() => {
                        axios
                          .post(deleteUrlWithSession, {
                            siteId: data?.id,
                          })
                          .then((res) => {
                            if (res.data.success) {
                              toast.success('Site deleted successfully', {
                                duration: 2000,
                              });
                              setTimeout(() => {
                                router.push('/dashboard');
                              }, 2000);
                            } else {
                              toast.error('Site deletion failed');
                            }
                          });
                      }}>
                      Delete
                    </button>
                  </div>
                </div>
              </Transition.Child>
            </div>
          </Dialog>
        </Transition>
      </div>
    </div>
  );
}