app.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { useState } from 'react'
  2. import copy from 'copy-to-clipboard'
  3. import { CheckIcon, DocumentDuplicateIcon } from '@heroicons/react/24/outline'
  4. import Store from 'electron-store'
  5. import { getCurrentWindow, app } from '@electron/remote'
  6. import { install } from './install'
  7. import OllamaIcon from './ollama.svg'
  8. const store = new Store()
  9. enum Step {
  10. WELCOME = 0,
  11. CLI,
  12. FINISH,
  13. }
  14. export default function () {
  15. const [step, setStep] = useState<Step>(Step.WELCOME)
  16. const [commandCopied, setCommandCopied] = useState<boolean>(false)
  17. const command = 'ollama run llama3.2'
  18. return (
  19. <div className='drag'>
  20. <div className='mx-auto flex min-h-screen w-full flex-col justify-between bg-white px-4 pt-16'>
  21. {step === Step.WELCOME && (
  22. <>
  23. <div className='mx-auto text-center'>
  24. <h1 className='mb-6 mt-4 text-2xl tracking-tight text-gray-900'>Welcome to Ollama</h1>
  25. <p className='mx-auto w-[65%] text-sm text-gray-400'>
  26. Let's get you up and running with your own large language models.
  27. </p>
  28. <button
  29. onClick={() => setStep(Step.CLI)}
  30. className='no-drag rounded-dm mx-auto my-8 w-[40%] rounded-md bg-black px-4 py-2 text-sm text-white hover:brightness-110'
  31. >
  32. Next
  33. </button>
  34. </div>
  35. <div className='mx-auto'>
  36. <OllamaIcon />
  37. </div>
  38. </>
  39. )}
  40. {step === Step.CLI && (
  41. <>
  42. <div className='mx-auto flex flex-col space-y-28 text-center'>
  43. <h1 className='mt-4 text-2xl tracking-tight text-gray-900'>Install the command line</h1>
  44. <pre className='mx-auto text-4xl text-gray-400'>&gt; ollama</pre>
  45. <div className='mx-auto'>
  46. <button
  47. onClick={async () => {
  48. try {
  49. await install()
  50. setStep(Step.FINISH)
  51. } catch (e) {
  52. console.error('could not install: ', e)
  53. } finally {
  54. getCurrentWindow().show()
  55. getCurrentWindow().focus()
  56. }
  57. }}
  58. className='no-drag rounded-dm mx-auto w-[60%] rounded-md bg-black px-4 py-2 text-sm text-white hover:brightness-110'
  59. >
  60. Install
  61. </button>
  62. <p className='mx-auto my-4 w-[70%] text-xs text-gray-400'>
  63. You will be prompted for administrator access
  64. </p>
  65. </div>
  66. </div>
  67. </>
  68. )}
  69. {step === Step.FINISH && (
  70. <>
  71. <div className='mx-auto flex flex-col space-y-20 text-center'>
  72. <h1 className='mt-4 text-2xl tracking-tight text-gray-900'>Run your first model</h1>
  73. <div className='flex flex-col'>
  74. <div className='group relative flex items-center'>
  75. <pre className='language-none text-2xs w-full rounded-md bg-gray-100 px-4 py-3 text-start leading-normal'>
  76. {command}
  77. </pre>
  78. <button
  79. className={`no-drag absolute right-[5px] px-2 py-2 ${
  80. commandCopied
  81. ? 'text-gray-900 opacity-100 hover:cursor-auto'
  82. : 'text-gray-200 opacity-50 hover:cursor-pointer'
  83. } hover:font-bold hover:text-gray-900 group-hover:opacity-100`}
  84. onClick={() => {
  85. copy(command)
  86. setCommandCopied(true)
  87. setTimeout(() => setCommandCopied(false), 3000)
  88. }}
  89. >
  90. {commandCopied ? (
  91. <CheckIcon className='h-4 w-4 font-bold text-gray-500' />
  92. ) : (
  93. <DocumentDuplicateIcon className='h-4 w-4 text-gray-500' />
  94. )}
  95. </button>
  96. </div>
  97. <p className='mx-auto my-4 w-[70%] text-xs text-gray-400'>
  98. Run this command in your favorite terminal.
  99. </p>
  100. </div>
  101. <button
  102. onClick={() => {
  103. store.set('first-time-run', true)
  104. window.close()
  105. }}
  106. className='no-drag rounded-dm mx-auto w-[60%] rounded-md bg-black px-4 py-2 text-sm text-white hover:brightness-110'
  107. >
  108. Finish
  109. </button>
  110. </div>
  111. </>
  112. )}
  113. </div>
  114. </div>
  115. )
  116. }